From nobody Tue May 7 17:09:40 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1571072871; cv=none; d=zoho.com; s=zohoarc; b=Zxms/oB1yh4UY4mS3hzgm+73IWb/l1jyyRuRiFo8pF5HhTsxCWxp7Tnf0qs/ZPYHn5IaFhQACCQ8+dXIRa5hSL7c/9+GSqfQsUqC/eR2sinKbU0bba3X69VbvfDE34EtaGYMdCmRvnucMsr1E6L63HUuoOkOYO4nFeVrI6j8mR0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1571072871; h=Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:Message-ID:References:Sender:Subject:To; bh=2WhMiMHyjTJYRPhmXvdR+PJGd21CxseJL47iXqDYs7U=; b=Ujc59OiNqYGbGIgy8UcnFileR1tvHhBFxlw/kzvc6QhRNCZSt1stO4Pvk8IqB2z5VN3Ng34KitBRz/sftuZSfIm9vt8nvD5jSQI10jv5GOmzZRzyuqhBkDGcux59mnkak7pxa/m0M86dx7DOq21ckbm0fFYccgMI1jTcu3P7c1Q= ARC-Authentication-Results: i=1; mx.zoho.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1571072871891945.5078674759117; Mon, 14 Oct 2019 10:07:51 -0700 (PDT) Received: from localhost ([::1]:54070 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iK3oy-0008Fi-Cg for importer@patchew.org; Mon, 14 Oct 2019 13:07:48 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:39776) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iK33y-00063I-It for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:18 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iK33u-0007La-Ib for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:14 -0400 Received: from mail-wr1-x441.google.com ([2a00:1450:4864:20::441]:35299) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1iK33u-0007KT-7r for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:10 -0400 Received: by mail-wr1-x441.google.com with SMTP id v8so20444909wrt.2 for ; Mon, 14 Oct 2019 09:19:10 -0700 (PDT) Received: from 8c859074c0ff.ant.amazon.com.com (bzq-79-178-11-117.red.bezeqint.net. [79.178.11.117]) by smtp.gmail.com with ESMTPSA id c132sm28050861wme.27.2019.10.14.09.19.06 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 14 Oct 2019 09:19:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=2WhMiMHyjTJYRPhmXvdR+PJGd21CxseJL47iXqDYs7U=; b=KheT38e0yE/sdwxtGCEDRpMGIu+VOTCWy7+iZKzrf2Fnh42uIWa3Cq0Cg9Bb9yXLv4 003jEwVZPo/xCenRXeRcFB4C1lCgvbYIEYRU7z6l2z2Qs2GcqBSX17y2xP6bnk+7HzR9 UW4lgRt+QCT6yQ95rcE4G3UoLinU7UYAyR40uu0d6leBFs9YqUQjY0do3U0hsuSVtJ2s AindOvt8OXENXSE08/jdJv6J3xrKv+Nl+WTgo+BYubWgnshFVHW8dV3yCoL2AEplqsx2 IrMINSluuKVIzVSKsw2bk07DBrpGbPZviDeS09mYBDICiDvNSHfaVgjekJoP7SQIzWim SxpQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=2WhMiMHyjTJYRPhmXvdR+PJGd21CxseJL47iXqDYs7U=; b=cnN/hGEVWIxwToT0nghKuwYeumCaa88MF8rUAUZsfvhaQIn7toP27w74C/HlFK4lJb kMKqCrzjBd7oKkQOsC3PfFQR1/LAa8U+3drHOHWxvJUuETT/oUiCVg5eEZNL61vSLWSY vop6Byu6x4U7k4fRPtSx0uc2RKlcJ7bzKeIXb9uIHu9dW2+/d7mCE3++X3pQZGS9BS8g QIl5FgbtIaFXTmf6lduY7ZGHxJpOI2yXES134ySiU3uhdcIzYIg3ydDJvsqS/3i5idIM STG7K7qoaXp/7hALY2yyJqHkT6LojwdoBKOa9vBitY8fA42jaYlvKfOfIGrXejvtWkBZ S7CA== X-Gm-Message-State: APjAAAWWMFGjcKlrqBY4eStlbrDJqqbcKGYfaiUURHmW4vtNLAnqR/jd UvAAbuYftP51uunz+Ke0uC9B6ljLAHI= X-Google-Smtp-Source: APXvYqyGny+/3VVp7hLNt+YpDlWyMNttuE8A5LRpR69DhfV6VB2ctTUswcSwVcuOnrIIHx2yggH3qw== X-Received: by 2002:adf:ed43:: with SMTP id u3mr26479866wro.236.1571069948397; Mon, 14 Oct 2019 09:19:08 -0700 (PDT) From: Michael Rolnik To: qemu-devel@nongnu.org Subject: [PATCH v32 01/13] target/avr: Add outward facing interfaces and core CPU logic Date: Mon, 14 Oct 2019 19:18:31 +0300 Message-Id: <20191014161843.84845-2-mrolnik@gmail.com> X-Mailer: git-send-email 2.17.2 (Apple Git-113) In-Reply-To: <20191014161843.84845-1-mrolnik@gmail.com> References: <20191014161843.84845-1-mrolnik@gmail.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::441 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: thuth@redhat.com, Michael Rolnik , richard.henderson@linaro.org, Sarah Harris , dovgaluk@ispras.ru, imammedo@redhat.com, philmd@redhat.com, aleksandar.m.mail@gmail.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This includes: - CPU data structures - object model classes and functions - migration functions - GDB hooks Co-developed-by: Michael Rolnik Co-developed-by: Sarah Harris Signed-off-by: Michael Rolnik Signed-off-by: Sarah Harris Signed-off-by: Michael Rolnik Acked-by: Igor Mammedov --- gdb-xml/avr-cpu.xml | 49 ++++ target/avr/cpu-param.h | 37 +++ target/avr/cpu-qom.h | 54 ++++ target/avr/cpu.c | 576 +++++++++++++++++++++++++++++++++++++++++ target/avr/cpu.h | 254 ++++++++++++++++++ target/avr/gdbstub.c | 85 ++++++ target/avr/machine.c | 121 +++++++++ 7 files changed, 1176 insertions(+) create mode 100644 gdb-xml/avr-cpu.xml create mode 100644 target/avr/cpu-param.h create mode 100644 target/avr/cpu-qom.h create mode 100644 target/avr/cpu.c create mode 100644 target/avr/cpu.h create mode 100644 target/avr/gdbstub.c create mode 100644 target/avr/machine.c diff --git a/gdb-xml/avr-cpu.xml b/gdb-xml/avr-cpu.xml new file mode 100644 index 0000000000..c4747f5b40 --- /dev/null +++ b/gdb-xml/avr-cpu.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/target/avr/cpu-param.h b/target/avr/cpu-param.h new file mode 100644 index 0000000000..ccd1ea3429 --- /dev/null +++ b/target/avr/cpu-param.h @@ -0,0 +1,37 @@ +/* + * QEMU AVR CPU + * + * Copyright (c) 2019 Michael Rolnik + * + * 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 + * + */ + +#ifndef AVR_CPU_PARAM_H +#define AVR_CPU_PARAM_H 1 + +#define TARGET_LONG_BITS 32 +/* + * TARGET_PAGE_BITS cannot be more than 8 bits because + * 1. all IO registers occupy [0x0000 .. 0x00ff] address range, and they + * should be implemented as a device and not memory + * 2. SRAM starts at the address 0x0100 + */ +#define TARGET_PAGE_BITS 8 +#define TARGET_PHYS_ADDR_SPACE_BITS 24 +#define TARGET_VIRT_ADDR_SPACE_BITS 24 +#define NB_MMU_MODES 2 + + +#endif diff --git a/target/avr/cpu-qom.h b/target/avr/cpu-qom.h new file mode 100644 index 0000000000..e28b58c897 --- /dev/null +++ b/target/avr/cpu-qom.h @@ -0,0 +1,54 @@ +/* + * QEMU AVR CPU + * + * Copyright (c) 2019 Michael Rolnik + * + * 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 + * + */ + +#ifndef QEMU_AVR_QOM_H +#define QEMU_AVR_QOM_H + +#include "hw/core/cpu.h" + +#define TYPE_AVR_CPU "avr-cpu" + +#define AVR_CPU_CLASS(klass) \ + OBJECT_CLASS_CHECK(AVRCPUClass, (klass), TYPE_AVR_CPU) +#define AVR_CPU(obj) \ + OBJECT_CHECK(AVRCPU, (obj), TYPE_AVR_CPU) +#define AVR_CPU_GET_CLASS(obj) \ + OBJECT_GET_CLASS(AVRCPUClass, (obj), TYPE_AVR_CPU) + +/** + * AVRCPUClass: + * @parent_realize: The parent class' realize handler. + * @parent_reset: The parent class' reset handler. + * @vr: Version Register value. + * + * A AVR CPU model. + */ +typedef struct AVRCPUClass { + /*< private >*/ + CPUClass parent_class; + /*< public >*/ + DeviceRealize parent_realize; + void (*parent_reset)(CPUState *cpu); +} AVRCPUClass; + +typedef struct AVRCPU AVRCPU; + + +#endif /* !defined (QEMU_AVR_CPU_QOM_H) */ diff --git a/target/avr/cpu.c b/target/avr/cpu.c new file mode 100644 index 0000000000..dae56d7845 --- /dev/null +++ b/target/avr/cpu.c @@ -0,0 +1,576 @@ +/* + * QEMU AVR CPU + * + * Copyright (c) 2019 Michael Rolnik + * + * 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 + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/qemu-print.h" +#include "exec/exec-all.h" +#include "cpu.h" + +static void avr_cpu_set_pc(CPUState *cs, vaddr value) +{ + AVRCPU *cpu =3D AVR_CPU(cs); + + cpu->env.pc_w =3D value / 2; /* internally PC points to words */ +} + +static bool avr_cpu_has_work(CPUState *cs) +{ + AVRCPU *cpu =3D AVR_CPU(cs); + CPUAVRState *env =3D &cpu->env; + + return (cs->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_RE= SET)) + && cpu_interrupts_enabled(env); +} + +static void avr_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb) +{ + AVRCPU *cpu =3D AVR_CPU(cs); + CPUAVRState *env =3D &cpu->env; + + env->pc_w =3D tb->pc / 2; /* internally PC points to words */ +} + +static void avr_cpu_reset(CPUState *cs) +{ + AVRCPU *cpu =3D AVR_CPU(cs); + AVRCPUClass *mcc =3D AVR_CPU_GET_CLASS(cpu); + CPUAVRState *env =3D &cpu->env; + + mcc->parent_reset(cs); + + env->pc_w =3D 0; + env->sregI =3D 1; + env->sregC =3D 0; + env->sregZ =3D 0; + env->sregN =3D 0; + env->sregV =3D 0; + env->sregS =3D 0; + env->sregH =3D 0; + env->sregT =3D 0; + + env->rampD =3D 0; + env->rampX =3D 0; + env->rampY =3D 0; + env->rampZ =3D 0; + env->eind =3D 0; + env->sp =3D 0; + + env->skip =3D 0; + + memset(env->r, 0, sizeof(env->r)); + + tlb_flush(cs); +} + +static void avr_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) +{ + info->mach =3D bfd_arch_avr; + info->print_insn =3D NULL; +} + +static void avr_cpu_realizefn(DeviceState *dev, Error **errp) +{ + CPUState *cs =3D CPU(dev); + AVRCPUClass *mcc =3D AVR_CPU_GET_CLASS(dev); + Error *local_err =3D NULL; + + cpu_exec_realizefn(cs, &local_err); + if (local_err !=3D NULL) { + error_propagate(errp, local_err); + return; + } + qemu_init_vcpu(cs); + cpu_reset(cs); + + mcc->parent_realize(dev, errp); +} + +static void avr_cpu_set_int(void *opaque, int irq, int level) +{ + AVRCPU *cpu =3D opaque; + CPUAVRState *env =3D &cpu->env; + CPUState *cs =3D CPU(cpu); + + uint64_t mask =3D (1ull << irq); + if (level) { + env->intsrc |=3D mask; + cpu_interrupt(cs, CPU_INTERRUPT_HARD); + } else { + env->intsrc &=3D ~mask; + if (env->intsrc =3D=3D 0) { + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + } + } +} + +static void avr_cpu_initfn(Object *obj) +{ + AVRCPU *cpu =3D AVR_CPU(obj); + + cpu_set_cpustate_pointers(cpu); + +#ifndef CONFIG_USER_ONLY + /* Set the number of interrupts supported by the CPU. */ + qdev_init_gpio_in(DEVICE(cpu), avr_cpu_set_int, 57); +#endif +} + +static ObjectClass *avr_cpu_class_by_name(const char *cpu_model) +{ + ObjectClass *oc; + + oc =3D object_class_by_name(cpu_model); + if (object_class_dynamic_cast(oc, TYPE_AVR_CPU) =3D=3D NULL || + object_class_is_abstract(oc)) { + oc =3D NULL; + } + return oc; +} + +static void avr_cpu_dump_state(CPUState *cs, FILE *f, int flags) +{ + AVRCPU *cpu =3D AVR_CPU(cs); + CPUAVRState *env =3D &cpu->env; + int i; + + qemu_fprintf(f, "\n"); + qemu_fprintf(f, "PC: %06x\n", env->pc_w); + qemu_fprintf(f, "SP: %04x\n", env->sp); + qemu_fprintf(f, "rampD: %02x\n", env->rampD >> 16); + qemu_fprintf(f, "rampX: %02x\n", env->rampX >> 16); + qemu_fprintf(f, "rampY: %02x\n", env->rampY >> 16); + qemu_fprintf(f, "rampZ: %02x\n", env->rampZ >> 16); + qemu_fprintf(f, "EIND: %02x\n", env->eind >> 16); + qemu_fprintf(f, "X: %02x%02x\n", env->r[27], env->r[26]); + qemu_fprintf(f, "Y: %02x%02x\n", env->r[29], env->r[28]); + qemu_fprintf(f, "Z: %02x%02x\n", env->r[31], env->r[30]); + qemu_fprintf(f, "SREG: [ %c %c %c %c %c %c %c %c ]\n", + env->sregI ? 'I' : '-', + env->sregT ? 'T' : '-', + env->sregH ? 'H' : '-', + env->sregS ? 'S' : '-', + env->sregV ? 'V' : '-', + env->sregN ? '-' : 'N', /* Zf has negative logic */ + env->sregZ ? 'Z' : '-', + env->sregC ? 'I' : '-'); + qemu_fprintf(f, "SKIP: %02x\n", env->skip); + + qemu_fprintf(f, "\n"); + for (i =3D 0; i < ARRAY_SIZE(env->r); i++) { + qemu_fprintf(f, "R[%02d]: %02x ", i, env->r[i]); + + if ((i % 8) =3D=3D 7) { + qemu_fprintf(f, "\n"); + } + } + qemu_fprintf(f, "\n"); +} + +static void avr_cpu_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(oc); + CPUClass *cc =3D CPU_CLASS(oc); + AVRCPUClass *mcc =3D AVR_CPU_CLASS(oc); + + mcc->parent_realize =3D dc->realize; + dc->realize =3D avr_cpu_realizefn; + + mcc->parent_reset =3D cc->reset; + cc->reset =3D avr_cpu_reset; + + cc->class_by_name =3D avr_cpu_class_by_name; + + cc->has_work =3D avr_cpu_has_work; + cc->do_interrupt =3D avr_cpu_do_interrupt; + cc->cpu_exec_interrupt =3D avr_cpu_exec_interrupt; + cc->dump_state =3D avr_cpu_dump_state; + cc->set_pc =3D avr_cpu_set_pc; +#if !defined(CONFIG_USER_ONLY) + cc->memory_rw_debug =3D avr_cpu_memory_rw_debug; +#endif +#ifdef CONFIG_USER_ONLY + cc->handle_mmu_fault =3D avr_cpu_handle_mmu_fault; +#else + cc->get_phys_page_debug =3D avr_cpu_get_phys_page_debug; + cc->vmsd =3D &vms_avr_cpu; +#endif + cc->disas_set_info =3D avr_cpu_disas_set_info; + cc->tlb_fill =3D avr_cpu_tlb_fill; + cc->tcg_initialize =3D avr_cpu_tcg_init; + cc->synchronize_from_tb =3D avr_cpu_synchronize_from_tb; + cc->gdb_read_register =3D avr_cpu_gdb_read_register; + cc->gdb_write_register =3D avr_cpu_gdb_write_register; + cc->gdb_num_core_regs =3D 35; + cc->gdb_core_xml_file =3D "avr-cpu.xml"; +} + +static void avr_avr1_initfn(Object *obj) +{ + AVRCPU *cpu =3D AVR_CPU(obj); + CPUAVRState *env =3D &cpu->env; + + avr_set_feature(env, AVR_FEATURE_LPM); + avr_set_feature(env, AVR_FEATURE_2_BYTE_SP); + avr_set_feature(env, AVR_FEATURE_2_BYTE_PC); +} + +static void avr_avr2_initfn(Object *obj) +{ + AVRCPU *cpu =3D AVR_CPU(obj); + CPUAVRState *env =3D &cpu->env; + + avr_set_feature(env, AVR_FEATURE_LPM); + avr_set_feature(env, AVR_FEATURE_IJMP_ICALL); + avr_set_feature(env, AVR_FEATURE_ADIW_SBIW); + avr_set_feature(env, AVR_FEATURE_SRAM); + avr_set_feature(env, AVR_FEATURE_BREAK); + + avr_set_feature(env, AVR_FEATURE_2_BYTE_PC); + avr_set_feature(env, AVR_FEATURE_2_BYTE_SP); +} + +static void avr_avr25_initfn(Object *obj) +{ + AVRCPU *cpu =3D AVR_CPU(obj); + CPUAVRState *env =3D &cpu->env; + + avr_set_feature(env, AVR_FEATURE_LPM); + avr_set_feature(env, AVR_FEATURE_IJMP_ICALL); + avr_set_feature(env, AVR_FEATURE_ADIW_SBIW); + avr_set_feature(env, AVR_FEATURE_SRAM); + avr_set_feature(env, AVR_FEATURE_BREAK); + + avr_set_feature(env, AVR_FEATURE_2_BYTE_PC); + avr_set_feature(env, AVR_FEATURE_2_BYTE_SP); + avr_set_feature(env, AVR_FEATURE_LPMX); + avr_set_feature(env, AVR_FEATURE_MOVW); +} + +static void avr_avr3_initfn(Object *obj) +{ + AVRCPU *cpu =3D AVR_CPU(obj); + CPUAVRState *env =3D &cpu->env; + + avr_set_feature(env, AVR_FEATURE_LPM); + avr_set_feature(env, AVR_FEATURE_IJMP_ICALL); + avr_set_feature(env, AVR_FEATURE_ADIW_SBIW); + avr_set_feature(env, AVR_FEATURE_SRAM); + avr_set_feature(env, AVR_FEATURE_BREAK); + + avr_set_feature(env, AVR_FEATURE_2_BYTE_PC); + avr_set_feature(env, AVR_FEATURE_2_BYTE_SP); + avr_set_feature(env, AVR_FEATURE_JMP_CALL); +} + +static void avr_avr31_initfn(Object *obj) +{ + AVRCPU *cpu =3D AVR_CPU(obj); + CPUAVRState *env =3D &cpu->env; + + avr_set_feature(env, AVR_FEATURE_LPM); + avr_set_feature(env, AVR_FEATURE_IJMP_ICALL); + avr_set_feature(env, AVR_FEATURE_ADIW_SBIW); + avr_set_feature(env, AVR_FEATURE_SRAM); + avr_set_feature(env, AVR_FEATURE_BREAK); + + avr_set_feature(env, AVR_FEATURE_2_BYTE_PC); + avr_set_feature(env, AVR_FEATURE_2_BYTE_SP); + avr_set_feature(env, AVR_FEATURE_RAMPZ); + avr_set_feature(env, AVR_FEATURE_ELPM); + avr_set_feature(env, AVR_FEATURE_JMP_CALL); +} + +static void avr_avr35_initfn(Object *obj) +{ + AVRCPU *cpu =3D AVR_CPU(obj); + CPUAVRState *env =3D &cpu->env; + + avr_set_feature(env, AVR_FEATURE_LPM); + avr_set_feature(env, AVR_FEATURE_IJMP_ICALL); + avr_set_feature(env, AVR_FEATURE_ADIW_SBIW); + avr_set_feature(env, AVR_FEATURE_SRAM); + avr_set_feature(env, AVR_FEATURE_BREAK); + + avr_set_feature(env, AVR_FEATURE_2_BYTE_PC); + avr_set_feature(env, AVR_FEATURE_2_BYTE_SP); + avr_set_feature(env, AVR_FEATURE_JMP_CALL); + avr_set_feature(env, AVR_FEATURE_LPMX); + avr_set_feature(env, AVR_FEATURE_MOVW); +} + +static void avr_avr4_initfn(Object *obj) +{ + AVRCPU *cpu =3D AVR_CPU(obj); + CPUAVRState *env =3D &cpu->env; + + avr_set_feature(env, AVR_FEATURE_LPM); + avr_set_feature(env, AVR_FEATURE_IJMP_ICALL); + avr_set_feature(env, AVR_FEATURE_ADIW_SBIW); + avr_set_feature(env, AVR_FEATURE_SRAM); + avr_set_feature(env, AVR_FEATURE_BREAK); + + avr_set_feature(env, AVR_FEATURE_2_BYTE_PC); + avr_set_feature(env, AVR_FEATURE_2_BYTE_SP); + avr_set_feature(env, AVR_FEATURE_LPMX); + avr_set_feature(env, AVR_FEATURE_MOVW); + avr_set_feature(env, AVR_FEATURE_MUL); +} + +static void avr_avr5_initfn(Object *obj) +{ + AVRCPU *cpu =3D AVR_CPU(obj); + CPUAVRState *env =3D &cpu->env; + + avr_set_feature(env, AVR_FEATURE_LPM); + avr_set_feature(env, AVR_FEATURE_IJMP_ICALL); + avr_set_feature(env, AVR_FEATURE_ADIW_SBIW); + avr_set_feature(env, AVR_FEATURE_SRAM); + avr_set_feature(env, AVR_FEATURE_BREAK); + + avr_set_feature(env, AVR_FEATURE_2_BYTE_PC); + avr_set_feature(env, AVR_FEATURE_2_BYTE_SP); + avr_set_feature(env, AVR_FEATURE_JMP_CALL); + avr_set_feature(env, AVR_FEATURE_LPMX); + avr_set_feature(env, AVR_FEATURE_MOVW); + avr_set_feature(env, AVR_FEATURE_MUL); +} + +static void avr_avr51_initfn(Object *obj) +{ + AVRCPU *cpu =3D AVR_CPU(obj); + CPUAVRState *env =3D &cpu->env; + + avr_set_feature(env, AVR_FEATURE_LPM); + avr_set_feature(env, AVR_FEATURE_IJMP_ICALL); + avr_set_feature(env, AVR_FEATURE_ADIW_SBIW); + avr_set_feature(env, AVR_FEATURE_SRAM); + avr_set_feature(env, AVR_FEATURE_BREAK); + + avr_set_feature(env, AVR_FEATURE_2_BYTE_PC); + avr_set_feature(env, AVR_FEATURE_2_BYTE_SP); + avr_set_feature(env, AVR_FEATURE_RAMPZ); + avr_set_feature(env, AVR_FEATURE_ELPMX); + avr_set_feature(env, AVR_FEATURE_ELPM); + avr_set_feature(env, AVR_FEATURE_JMP_CALL); + avr_set_feature(env, AVR_FEATURE_LPMX); + avr_set_feature(env, AVR_FEATURE_MOVW); + avr_set_feature(env, AVR_FEATURE_MUL); +} + +static void avr_avr6_initfn(Object *obj) +{ + AVRCPU *cpu =3D AVR_CPU(obj); + CPUAVRState *env =3D &cpu->env; + + avr_set_feature(env, AVR_FEATURE_LPM); + avr_set_feature(env, AVR_FEATURE_IJMP_ICALL); + avr_set_feature(env, AVR_FEATURE_ADIW_SBIW); + avr_set_feature(env, AVR_FEATURE_SRAM); + avr_set_feature(env, AVR_FEATURE_BREAK); + + avr_set_feature(env, AVR_FEATURE_3_BYTE_PC); + avr_set_feature(env, AVR_FEATURE_2_BYTE_SP); + avr_set_feature(env, AVR_FEATURE_RAMPZ); + avr_set_feature(env, AVR_FEATURE_EIJMP_EICALL); + avr_set_feature(env, AVR_FEATURE_ELPMX); + avr_set_feature(env, AVR_FEATURE_ELPM); + avr_set_feature(env, AVR_FEATURE_JMP_CALL); + avr_set_feature(env, AVR_FEATURE_LPMX); + avr_set_feature(env, AVR_FEATURE_MOVW); + avr_set_feature(env, AVR_FEATURE_MUL); +} + +static void avr_xmega2_initfn(Object *obj) +{ + AVRCPU *cpu =3D AVR_CPU(obj); + CPUAVRState *env =3D &cpu->env; + + avr_set_feature(env, AVR_FEATURE_LPM); + avr_set_feature(env, AVR_FEATURE_IJMP_ICALL); + avr_set_feature(env, AVR_FEATURE_ADIW_SBIW); + avr_set_feature(env, AVR_FEATURE_SRAM); + avr_set_feature(env, AVR_FEATURE_BREAK); + + avr_set_feature(env, AVR_FEATURE_2_BYTE_PC); + avr_set_feature(env, AVR_FEATURE_2_BYTE_SP); + avr_set_feature(env, AVR_FEATURE_JMP_CALL); + avr_set_feature(env, AVR_FEATURE_LPMX); + avr_set_feature(env, AVR_FEATURE_MOVW); + avr_set_feature(env, AVR_FEATURE_MUL); + avr_set_feature(env, AVR_FEATURE_RMW); +} + +static void avr_xmega4_initfn(Object *obj) +{ + AVRCPU *cpu =3D AVR_CPU(obj); + CPUAVRState *env =3D &cpu->env; + + avr_set_feature(env, AVR_FEATURE_LPM); + avr_set_feature(env, AVR_FEATURE_IJMP_ICALL); + avr_set_feature(env, AVR_FEATURE_ADIW_SBIW); + avr_set_feature(env, AVR_FEATURE_SRAM); + avr_set_feature(env, AVR_FEATURE_BREAK); + + avr_set_feature(env, AVR_FEATURE_2_BYTE_PC); + avr_set_feature(env, AVR_FEATURE_2_BYTE_SP); + avr_set_feature(env, AVR_FEATURE_RAMPZ); + avr_set_feature(env, AVR_FEATURE_ELPMX); + avr_set_feature(env, AVR_FEATURE_ELPM); + avr_set_feature(env, AVR_FEATURE_JMP_CALL); + avr_set_feature(env, AVR_FEATURE_LPMX); + avr_set_feature(env, AVR_FEATURE_MOVW); + avr_set_feature(env, AVR_FEATURE_MUL); + avr_set_feature(env, AVR_FEATURE_RMW); +} + +static void avr_xmega5_initfn(Object *obj) +{ + AVRCPU *cpu =3D AVR_CPU(obj); + CPUAVRState *env =3D &cpu->env; + + avr_set_feature(env, AVR_FEATURE_LPM); + avr_set_feature(env, AVR_FEATURE_IJMP_ICALL); + avr_set_feature(env, AVR_FEATURE_ADIW_SBIW); + avr_set_feature(env, AVR_FEATURE_SRAM); + avr_set_feature(env, AVR_FEATURE_BREAK); + + avr_set_feature(env, AVR_FEATURE_2_BYTE_PC); + avr_set_feature(env, AVR_FEATURE_2_BYTE_SP); + avr_set_feature(env, AVR_FEATURE_RAMPD); + avr_set_feature(env, AVR_FEATURE_RAMPX); + avr_set_feature(env, AVR_FEATURE_RAMPY); + avr_set_feature(env, AVR_FEATURE_RAMPZ); + avr_set_feature(env, AVR_FEATURE_ELPMX); + avr_set_feature(env, AVR_FEATURE_ELPM); + avr_set_feature(env, AVR_FEATURE_JMP_CALL); + avr_set_feature(env, AVR_FEATURE_LPMX); + avr_set_feature(env, AVR_FEATURE_MOVW); + avr_set_feature(env, AVR_FEATURE_MUL); + avr_set_feature(env, AVR_FEATURE_RMW); +} + +static void avr_xmega6_initfn(Object *obj) +{ + AVRCPU *cpu =3D AVR_CPU(obj); + CPUAVRState *env =3D &cpu->env; + + avr_set_feature(env, AVR_FEATURE_LPM); + avr_set_feature(env, AVR_FEATURE_IJMP_ICALL); + avr_set_feature(env, AVR_FEATURE_ADIW_SBIW); + avr_set_feature(env, AVR_FEATURE_SRAM); + avr_set_feature(env, AVR_FEATURE_BREAK); + + avr_set_feature(env, AVR_FEATURE_3_BYTE_PC); + avr_set_feature(env, AVR_FEATURE_2_BYTE_SP); + avr_set_feature(env, AVR_FEATURE_RAMPZ); + avr_set_feature(env, AVR_FEATURE_EIJMP_EICALL); + avr_set_feature(env, AVR_FEATURE_ELPMX); + avr_set_feature(env, AVR_FEATURE_ELPM); + avr_set_feature(env, AVR_FEATURE_JMP_CALL); + avr_set_feature(env, AVR_FEATURE_LPMX); + avr_set_feature(env, AVR_FEATURE_MOVW); + avr_set_feature(env, AVR_FEATURE_MUL); + avr_set_feature(env, AVR_FEATURE_RMW); +} + +static void avr_xmega7_initfn(Object *obj) +{ + AVRCPU *cpu =3D AVR_CPU(obj); + CPUAVRState *env =3D &cpu->env; + + avr_set_feature(env, AVR_FEATURE_LPM); + avr_set_feature(env, AVR_FEATURE_IJMP_ICALL); + avr_set_feature(env, AVR_FEATURE_ADIW_SBIW); + avr_set_feature(env, AVR_FEATURE_SRAM); + avr_set_feature(env, AVR_FEATURE_BREAK); + + avr_set_feature(env, AVR_FEATURE_3_BYTE_PC); + avr_set_feature(env, AVR_FEATURE_2_BYTE_SP); + avr_set_feature(env, AVR_FEATURE_RAMPD); + avr_set_feature(env, AVR_FEATURE_RAMPX); + avr_set_feature(env, AVR_FEATURE_RAMPY); + avr_set_feature(env, AVR_FEATURE_RAMPZ); + avr_set_feature(env, AVR_FEATURE_EIJMP_EICALL); + avr_set_feature(env, AVR_FEATURE_ELPMX); + avr_set_feature(env, AVR_FEATURE_ELPM); + avr_set_feature(env, AVR_FEATURE_JMP_CALL); + avr_set_feature(env, AVR_FEATURE_LPMX); + avr_set_feature(env, AVR_FEATURE_MOVW); + avr_set_feature(env, AVR_FEATURE_MUL); + avr_set_feature(env, AVR_FEATURE_RMW); +} + +typedef struct AVRCPUInfo { + const char *name; + void (*initfn)(Object *obj); +} AVRCPUInfo; + + +static void avr_cpu_list_entry(gpointer data, gpointer user_data) +{ + const char *typename =3D object_class_get_name(OBJECT_CLASS(data)); + + qemu_printf("%s\n", typename); +} + +void avr_cpu_list(void) +{ + GSList *list; + list =3D object_class_get_list_sorted(TYPE_AVR_CPU, false); + g_slist_foreach(list, avr_cpu_list_entry, NULL); + g_slist_free(list); +} + +#define DEFINE_AVR_CPU_TYPE(model, initfn) \ + { \ + .parent =3D TYPE_AVR_CPU, \ + .instance_init =3D initfn, \ + .name =3D model "-avr-cpu", \ + } + +static const TypeInfo avr_cpu_type_info[] =3D { + { + .name =3D TYPE_AVR_CPU, + .parent =3D TYPE_CPU, + .instance_size =3D sizeof(AVRCPU), + .instance_init =3D avr_cpu_initfn, + .class_size =3D sizeof(AVRCPUClass), + .class_init =3D avr_cpu_class_init, + .abstract =3D true, + }, + DEFINE_AVR_CPU_TYPE("avr1", avr_avr1_initfn), + DEFINE_AVR_CPU_TYPE("avr2", avr_avr2_initfn), + DEFINE_AVR_CPU_TYPE("avr25", avr_avr25_initfn), + DEFINE_AVR_CPU_TYPE("avr3", avr_avr3_initfn), + DEFINE_AVR_CPU_TYPE("avr31", avr_avr31_initfn), + DEFINE_AVR_CPU_TYPE("avr35", avr_avr35_initfn), + DEFINE_AVR_CPU_TYPE("avr4", avr_avr4_initfn), + DEFINE_AVR_CPU_TYPE("avr5", avr_avr5_initfn), + DEFINE_AVR_CPU_TYPE("avr51", avr_avr51_initfn), + DEFINE_AVR_CPU_TYPE("avr6", avr_avr6_initfn), + DEFINE_AVR_CPU_TYPE("xmega2", avr_xmega2_initfn), + DEFINE_AVR_CPU_TYPE("xmega4", avr_xmega4_initfn), + DEFINE_AVR_CPU_TYPE("xmega5", avr_xmega5_initfn), + DEFINE_AVR_CPU_TYPE("xmega6", avr_xmega6_initfn), + DEFINE_AVR_CPU_TYPE("xmega7", avr_xmega7_initfn), +}; + +DEFINE_TYPES(avr_cpu_type_info) diff --git a/target/avr/cpu.h b/target/avr/cpu.h new file mode 100644 index 0000000000..45d644f4f4 --- /dev/null +++ b/target/avr/cpu.h @@ -0,0 +1,254 @@ +/* + * QEMU AVR CPU + * + * Copyright (c) 2019 Michael Rolnik + * + * 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 + * + */ + +#ifndef QEMU_AVR_CPU_H +#define QEMU_AVR_CPU_H + +#include "cpu-qom.h" +#include "exec/cpu-defs.h" + +#define TCG_GUEST_DEFAULT_MO 0 + +#define CPU_RESOLVING_TYPE TYPE_AVR_CPU + +/* + * AVR has two memory spaces, data & code. + * e.g. both have 0 address + * ST/LD instructions access data space + * LPM/SPM and instruction fetching access code memory space + */ +#define MMU_CODE_IDX 0 +#define MMU_DATA_IDX 1 + +#define EXCP_RESET 1 +#define EXCP_INT(n) (EXCP_RESET + (n) + 1) + +/* Number of CPU registers */ +#define NO_CPU_REGISTERS 32 +/* Number of IO registers accessible by ld/st/in/out */ +#define NO_IO_REGISTERS 64 + +/* + * Offsets of AVR memory regions in host memory space. + * + * This is needed because the AVR has separate code and data address + * spaces that both have start from zero but have to go somewhere in + * host memory. + * + * It's also useful to know where some things are, like the IO registers. + */ +/* Flash program memory */ +#define OFFSET_CODE 0x00000000 +/* CPU registers, IO registers, and SRAM */ +#define OFFSET_DATA 0x00800000 +/* CPU registers specifically, these are mapped at the start of data */ +#define OFFSET_CPU_REGISTERS OFFSET_DATA +/* + * IO registers, including status register, stack pointer, and memory + * mapped peripherals, mapped just after CPU registers + */ +#define OFFSET_IO_REGISTERS (OFFSET_DATA + NO_CPU_REGISTERS) + +enum avr_features { + AVR_FEATURE_SRAM, + + AVR_FEATURE_1_BYTE_PC, + AVR_FEATURE_2_BYTE_PC, + AVR_FEATURE_3_BYTE_PC, + + AVR_FEATURE_1_BYTE_SP, + AVR_FEATURE_2_BYTE_SP, + + AVR_FEATURE_BREAK, + AVR_FEATURE_DES, + AVR_FEATURE_RMW, /* Read Modify Write - XCH LAC LAS LAT */ + + AVR_FEATURE_EIJMP_EICALL, + AVR_FEATURE_IJMP_ICALL, + AVR_FEATURE_JMP_CALL, + + AVR_FEATURE_ADIW_SBIW, + + AVR_FEATURE_SPM, + AVR_FEATURE_SPMX, + + AVR_FEATURE_ELPMX, + AVR_FEATURE_ELPM, + AVR_FEATURE_LPMX, + AVR_FEATURE_LPM, + + AVR_FEATURE_MOVW, + AVR_FEATURE_MUL, + AVR_FEATURE_RAMPD, + AVR_FEATURE_RAMPX, + AVR_FEATURE_RAMPY, + AVR_FEATURE_RAMPZ, +}; + +typedef struct CPUAVRState CPUAVRState; + +struct CPUAVRState { + uint32_t pc_w; /* 0x003fffff up to 22 bits */ + + uint32_t sregC; /* 0x00000001 1 bits */ + uint32_t sregZ; /* 0x0000ffff 16 bits, negative logic; */ + /* 0=3Dflag set, >0=3Dflag cleared */ + uint32_t sregN; /* 0x00000001 1 bits */ + uint32_t sregV; /* 0x00000001 1 bits */ + uint32_t sregS; /* 0x00000001 1 bits */ + uint32_t sregH; /* 0x00000001 1 bits */ + uint32_t sregT; /* 0x00000001 1 bits */ + uint32_t sregI; /* 0x00000001 1 bits */ + + uint32_t rampD; /* 0x00ff0000 8 bits */ + uint32_t rampX; /* 0x00ff0000 8 bits */ + uint32_t rampY; /* 0x00ff0000 8 bits */ + uint32_t rampZ; /* 0x00ff0000 8 bits */ + uint32_t eind; /* 0x00ff0000 8 bits */ + + uint32_t r[NO_CPU_REGISTERS]; /* 8 bits each */ + uint32_t sp; /* 16 bits */ + + uint32_t skip; /* if set skip instruction */ + + uint64_t intsrc; /* interrupt sources */ + bool fullacc; /* CPU/MEM if true MEM only otherwise */ + + uint32_t features; +}; + +/** + * AVRCPU: + * @env: #CPUAVRState + * + * A AVR CPU. + */ +typedef struct AVRCPU { + /*< private >*/ + CPUState parent_obj; + /*< public >*/ + + CPUNegativeOffsetState neg; + CPUAVRState env; +} AVRCPU; + +#ifndef CONFIG_USER_ONLY +extern const struct VMStateDescription vms_avr_cpu; +#endif + +void avr_cpu_do_interrupt(CPUState *cpu); +bool avr_cpu_exec_interrupt(CPUState *cpu, int int_req); +hwaddr avr_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); +int avr_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); +int avr_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); + +static inline int avr_feature(CPUAVRState *env, int feature) +{ + return (env->features & (1U << feature)) !=3D 0; +} + +static inline void avr_set_feature(CPUAVRState *env, int feature) +{ + env->features |=3D (1U << feature); +} + +#define cpu_list avr_cpu_list +#define cpu_signal_handler cpu_avr_signal_handler +#define cpu_mmu_index avr_cpu_mmu_index + +static inline int avr_cpu_mmu_index(CPUAVRState *env, bool ifetch) +{ + return ifetch ? MMU_CODE_IDX : MMU_DATA_IDX; +} + +void avr_cpu_tcg_init(void); + +void avr_cpu_list(void); +int cpu_avr_exec(CPUState *cpu); +int cpu_avr_signal_handler(int host_signum, void *pinfo, void *puc); +int avr_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int size, + int rw, int mmu_idx); +int avr_cpu_memory_rw_debug(CPUState *cs, vaddr address, uint8_t *buf, + int len, bool is_write); + +enum { + TB_FLAGS_FULL_ACCESS =3D 1, + TB_FLAGS_SKIP =3D 2, +}; + +static inline void cpu_get_tb_cpu_state(CPUAVRState *env, target_ulong *pc, + target_ulong *cs_base, uint32_t *pflags) +{ + uint32_t flags =3D 0; + + *pc =3D env->pc_w * 2; + *cs_base =3D 0; + + if (env->fullacc) { + flags |=3D TB_FLAGS_FULL_ACCESS; + } + if (env->skip) { + flags |=3D TB_FLAGS_SKIP; + } + + *pflags =3D flags; +} + +static inline int cpu_interrupts_enabled(CPUAVRState *env) +{ + return env->sregI !=3D 0; +} + +static inline uint8_t cpu_get_sreg(CPUAVRState *env) +{ + uint8_t sreg; + sreg =3D (env->sregC & 0x01) << 0 + | (env->sregZ =3D=3D 0 ? 1 : 0) << 1 + | (env->sregN) << 2 + | (env->sregV) << 3 + | (env->sregS) << 4 + | (env->sregH) << 5 + | (env->sregT) << 6 + | (env->sregI) << 7; + return sreg; +} + +static inline void cpu_set_sreg(CPUAVRState *env, uint8_t sreg) +{ + env->sregC =3D (sreg >> 0) & 0x01; + env->sregZ =3D (sreg >> 1) & 0x01 ? 0 : 1; + env->sregN =3D (sreg >> 2) & 0x01; + env->sregV =3D (sreg >> 3) & 0x01; + env->sregS =3D (sreg >> 4) & 0x01; + env->sregH =3D (sreg >> 5) & 0x01; + env->sregT =3D (sreg >> 6) & 0x01; + env->sregI =3D (sreg >> 7) & 0x01; +} + +bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size, + MMUAccessType access_type, int mmu_idx, + bool probe, uintptr_t retaddr); + +typedef CPUAVRState CPUArchState; +typedef AVRCPU ArchCPU; + +#include "exec/cpu-all.h" + +#endif /* !defined (QEMU_AVR_CPU_H) */ diff --git a/target/avr/gdbstub.c b/target/avr/gdbstub.c new file mode 100644 index 0000000000..20a5252482 --- /dev/null +++ b/target/avr/gdbstub.c @@ -0,0 +1,85 @@ +/* + * QEMU AVR CPU + * + * Copyright (c) 2019 Michael Rolnik + * + * 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 + * + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "exec/gdbstub.h" + +int avr_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + AVRCPU *cpu =3D AVR_CPU(cs); + CPUAVRState *env =3D &cpu->env; + + /* R */ + if (n < 32) { + return gdb_get_reg8(mem_buf, env->r[n]); + } + + /* SREG */ + if (n =3D=3D 32) { + uint8_t sreg =3D cpu_get_sreg(env); + + return gdb_get_reg8(mem_buf, sreg); + } + + /* SP */ + if (n =3D=3D 33) { + return gdb_get_reg16(mem_buf, env->sp & 0x0000ffff); + } + + /* PC */ + if (n =3D=3D 34) { + return gdb_get_reg32(mem_buf, env->pc_w * 2); + } + + return 0; +} + +int avr_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + AVRCPU *cpu =3D AVR_CPU(cs); + CPUAVRState *env =3D &cpu->env; + + /* R */ + if (n < 32) { + env->r[n] =3D *mem_buf; + return 1; + } + + /* SREG */ + if (n =3D=3D 32) { + cpu_set_sreg(env, *mem_buf); + return 1; + } + + /* SP */ + if (n =3D=3D 33) { + env->sp =3D lduw_p(mem_buf); + return 2; + } + + /* PC */ + if (n =3D=3D 34) { + env->pc_w =3D ldl_p(mem_buf) / 2; + return 4; + } + + return 0; +} diff --git a/target/avr/machine.c b/target/avr/machine.c new file mode 100644 index 0000000000..f6dcda7adc --- /dev/null +++ b/target/avr/machine.c @@ -0,0 +1,121 @@ +/* + * QEMU AVR CPU + * + * Copyright (c) 2019 Michael Rolnik + * + * 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 + * + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "migration/cpu.h" + +static int get_sreg(QEMUFile *f, void *opaque, size_t size, + const VMStateField *field) +{ + CPUAVRState *env =3D opaque; + uint8_t sreg; + + sreg =3D qemu_get_byte(f); + cpu_set_sreg(env, sreg); + return 0; +} + +static int put_sreg( + QEMUFile *f, void *opaque, size_t size, + const VMStateField *field, QJSON *vmdesc) +{ + CPUAVRState *env =3D opaque; + uint8_t sreg =3D cpu_get_sreg(env); + + qemu_put_byte(f, sreg); + return 0; +} + +static const VMStateInfo vms_sreg =3D { + .name =3D "sreg", + .get =3D get_sreg, + .put =3D put_sreg, +}; + +static int get_segment( + QEMUFile *f, void *opaque, size_t size, const VMStateField *field) +{ + uint32_t *ramp =3D opaque; + uint8_t temp; + + temp =3D qemu_get_byte(f); + *ramp =3D ((uint32_t)temp) << 16; + return 0; +} + +static int put_segment( + QEMUFile *f, void *opaque, size_t size, + const VMStateField *field, QJSON *vmdesc) +{ + uint32_t *ramp =3D opaque; + uint8_t temp =3D *ramp >> 16; + + qemu_put_byte(f, temp); + return 0; +} + +static const VMStateInfo vms_rampD =3D { + .name =3D "rampD", + .get =3D get_segment, + .put =3D put_segment, +}; +static const VMStateInfo vms_rampX =3D { + .name =3D "rampX", + .get =3D get_segment, + .put =3D put_segment, +}; +static const VMStateInfo vms_rampY =3D { + .name =3D "rampY", + .get =3D get_segment, + .put =3D put_segment, +}; +static const VMStateInfo vms_rampZ =3D { + .name =3D "rampZ", + .get =3D get_segment, + .put =3D put_segment, +}; +static const VMStateInfo vms_eind =3D { + .name =3D "eind", + .get =3D get_segment, + .put =3D put_segment, +}; + +const VMStateDescription vms_avr_cpu =3D { + .name =3D "cpu", + .version_id =3D 0, + .minimum_version_id =3D 0, + .fields =3D (VMStateField[]) { + VMSTATE_UINT32(env.pc_w, AVRCPU), + VMSTATE_UINT32(env.sp, AVRCPU), + VMSTATE_UINT32(env.skip, AVRCPU), + + VMSTATE_UINT32_ARRAY(env.r, AVRCPU, NO_CPU_REGISTERS), + + VMSTATE_SINGLE(env, AVRCPU, 0, vms_sreg, CPUAVRState), + VMSTATE_SINGLE(env.rampD, AVRCPU, 0, vms_rampD, uint32_t), + VMSTATE_SINGLE(env.rampX, AVRCPU, 0, vms_rampX, uint32_t), + VMSTATE_SINGLE(env.rampY, AVRCPU, 0, vms_rampY, uint32_t), + VMSTATE_SINGLE(env.rampZ, AVRCPU, 0, vms_rampZ, uint32_t), + VMSTATE_SINGLE(env.eind, AVRCPU, 0, vms_eind, uint32_t), + + VMSTATE_END_OF_LIST() + } +}; --=20 2.17.2 (Apple Git-113) From nobody Tue May 7 17:09:40 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1571072652; cv=none; d=zoho.com; s=zohoarc; b=oi5zqzMhhvRs3grjUWGmBXYf9M6qUVOsbbIgnidbKHOqKMKL+WF3mDbWricatjzDuVYmUQK4DgXVvoWZ0VaklH3flz8t0mOXZ92rwjj/SBSawH7ZzYMvJmaWb9rKwkzD1SN9fWme6flvzmBaYH+R5aoPSTOLMOb1XfzLnyTJc5E= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1571072652; h=Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:Message-ID:References:Sender:Subject:To; bh=Wrb/eh//pKqC5sqQg+JmF7gLP8TvTzApdrnvwmESS9w=; b=Qeeb9/jkZLKRzMHpm69zcm1ABR7bPauRlvSVE1eSg8qdvxTyUk2W9F81Oq7zRjrAqm9CLVMI1XVpCswe4rIzvcX4Z7uSOW2dC0yhXS/+ss/Es+m5PYodCXALU6yJvVehm4cgLvdALIwSjybT7LSo6dRkqrw+yKma4qyl+K1kVEc= ARC-Authentication-Results: i=1; mx.zoho.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1571072652741415.8635388288343; Mon, 14 Oct 2019 10:04:12 -0700 (PDT) Received: from localhost ([::1]:54011 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iK3lS-0004LP-S4 for importer@patchew.org; Mon, 14 Oct 2019 13:04:10 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:39774) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iK33y-00062l-8w for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:16 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iK33w-0007Ma-2I for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:14 -0400 Received: from mail-wm1-x334.google.com ([2a00:1450:4864:20::334]:51435) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1iK33v-0007Lz-Rg for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:12 -0400 Received: by mail-wm1-x334.google.com with SMTP id 7so17925411wme.1 for ; Mon, 14 Oct 2019 09:19:11 -0700 (PDT) Received: from 8c859074c0ff.ant.amazon.com.com (bzq-79-178-11-117.red.bezeqint.net. [79.178.11.117]) by smtp.gmail.com with ESMTPSA id c132sm28050861wme.27.2019.10.14.09.19.08 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 14 Oct 2019 09:19:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=Wrb/eh//pKqC5sqQg+JmF7gLP8TvTzApdrnvwmESS9w=; b=PWLxPQWPyUXqhQ7kOzg0kfalcfAGxqK1SdRf9jtdX8fv7eSrPPckmNQPj0k7APVYnb jlURwEWZNESImEkhI0Ydjp3CvDDNfOG/zsJ86CBauVsQfSaRstZVhwDbRJQGyfhRYrJq P2CSiMCeTf0cmZ6az1f78+I4R4P6oa862rvpmKj9LpPfINVSoWQABgTAxeYO5QHz15TR dNE8VOrAc9EosUBWPnp1Un7g/qy6UQu+slRs2OV7mVbrHQCkRvvZLqiHaCK9UZ+xSlvL eJ6PrJCoA1EuHZimOct8HUbEn7JRGLn36InqM9ALBXkjdmFrJyHoc6+wNm/n6fg+iVK+ euVQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=Wrb/eh//pKqC5sqQg+JmF7gLP8TvTzApdrnvwmESS9w=; b=qOkd5HtY8RRbKkxLEnJnCuWKx6VXnlsZseFGwIVZQXkeXacFEX7HjLt+2enDGTBtsy 3QLk592zjKn+/hnwA5bcIafWO5WscX4kWVULdwJmYmWyQdXJliduu/kVmcdCBrI6EA9U eNfOmjm0ky3pTQCMYsCE63dBgfwJZsaruBdhEFnBRtZCL+JcSOhc5Xy31WF1kZHZN+f6 629p41aTuL1OXFTs7IHHiR9Diwo7L8pcbP+wkX70R2NBaqB2nzGVJ0cQd+e72dlVXij6 UYTmANjFF2+cSPb3Tig9NIcQQ9an202rk1nrszo5FHyd4vR2qLTikkdMzu7qURd37Moo yMJA== X-Gm-Message-State: APjAAAWaCMDLmtfq9noBIPegHW2F/3QgF1oFkkJF0Mr67Q+bs3CoozNc lVpO1L2l5XBTuzRWOpWnV5VAR9V3BRA= X-Google-Smtp-Source: APXvYqwqeaXZX/lj1Caj17CgLDVTnrHQcFlyEBXf8eN6ge1jyA1eGpi08IZZndTX/k+qq6xSC5q4KA== X-Received: by 2002:a7b:c936:: with SMTP id h22mr15289414wml.1.1571069950348; Mon, 14 Oct 2019 09:19:10 -0700 (PDT) From: Michael Rolnik To: qemu-devel@nongnu.org Subject: [PATCH v32 02/13] target/avr: Add instruction helpers Date: Mon, 14 Oct 2019 19:18:32 +0300 Message-Id: <20191014161843.84845-3-mrolnik@gmail.com> X-Mailer: git-send-email 2.17.2 (Apple Git-113) In-Reply-To: <20191014161843.84845-1-mrolnik@gmail.com> References: <20191014161843.84845-1-mrolnik@gmail.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::334 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: thuth@redhat.com, Michael Rolnik , richard.henderson@linaro.org, dovgaluk@ispras.ru, imammedo@redhat.com, philmd@redhat.com, aleksandar.m.mail@gmail.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Stubs for unimplemented instructions and helpers for instructions that need= to interact with QEMU. SPM and WDR are unimplemented because they require emulation of complex per= ipherals. The implementation of SLEEP is very limited due to the lack of peripherals = to generate wake interrupts. Memory access instructions are implemented here because some address ranges= actually refer to CPU registers. Signed-off-by: Michael Rolnik --- target/avr/helper.c | 354 ++++++++++++++++++++++++++++++++++++++++++++ target/avr/helper.h | 29 ++++ 2 files changed, 383 insertions(+) create mode 100644 target/avr/helper.c create mode 100644 target/avr/helper.h diff --git a/target/avr/helper.c b/target/avr/helper.c new file mode 100644 index 0000000000..f0f0d4f15a --- /dev/null +++ b/target/avr/helper.c @@ -0,0 +1,354 @@ +/* + * QEMU AVR CPU + * + * Copyright (c) 2019 Michael Rolnik + * + * 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 + * + */ + +#include "qemu/osdep.h" + +#include "cpu.h" +#include "hw/irq.h" +#include "hw/sysbus.h" +#include "sysemu/sysemu.h" +#include "exec/exec-all.h" +#include "exec/cpu_ldst.h" +#include "exec/helper-proto.h" +#include "exec/ioport.h" +#include "qemu/host-utils.h" +#include "qemu/error-report.h" + +bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request) +{ + bool ret =3D false; + CPUClass *cc =3D CPU_GET_CLASS(cs); + AVRCPU *cpu =3D AVR_CPU(cs); + CPUAVRState *env =3D &cpu->env; + + if (interrupt_request & CPU_INTERRUPT_RESET) { + if (cpu_interrupts_enabled(env)) { + cs->exception_index =3D EXCP_RESET; + cc->do_interrupt(cs); + + cs->interrupt_request &=3D ~CPU_INTERRUPT_RESET; + + ret =3D true; + } + } + if (interrupt_request & CPU_INTERRUPT_HARD) { + if (cpu_interrupts_enabled(env) && env->intsrc !=3D 0) { + int index =3D ctz32(env->intsrc); + cs->exception_index =3D EXCP_INT(index); + cc->do_interrupt(cs); + + env->intsrc &=3D env->intsrc - 1; /* clear the interrupt */ + cs->interrupt_request &=3D ~CPU_INTERRUPT_HARD; + + ret =3D true; + } + } + return ret; +} + +void avr_cpu_do_interrupt(CPUState *cs) +{ + AVRCPU *cpu =3D AVR_CPU(cs); + CPUAVRState *env =3D &cpu->env; + + uint32_t ret =3D env->pc_w; + int vector =3D 0; + int size =3D avr_feature(env, AVR_FEATURE_JMP_CALL) ? 2 : 1; + int base =3D 0; + + if (cs->exception_index =3D=3D EXCP_RESET) { + vector =3D 0; + } else if (env->intsrc !=3D 0) { + vector =3D ctz32(env->intsrc) + 1; + } + + if (avr_feature(env, AVR_FEATURE_3_BYTE_PC)) { + cpu_stb_data(env, env->sp--, (ret & 0x0000ff)); + cpu_stb_data(env, env->sp--, (ret & 0x00ff00) >> 8); + cpu_stb_data(env, env->sp--, (ret & 0xff0000) >> 16); + } else if (avr_feature(env, AVR_FEATURE_2_BYTE_PC)) { + cpu_stb_data(env, env->sp--, (ret & 0x0000ff)); + cpu_stb_data(env, env->sp--, (ret & 0x00ff00) >> 8); + } else { + cpu_stb_data(env, env->sp--, (ret & 0x0000ff)); + } + + env->pc_w =3D base + vector * size; + env->sregI =3D 0; /* clear Global Interrupt Flag */ + + cs->exception_index =3D -1; +} + +int avr_cpu_memory_rw_debug(CPUState *cs, vaddr addr, uint8_t *buf, + int len, bool is_write) +{ + return cpu_memory_rw_debug(cs, addr, buf, len, is_write); +} + +hwaddr avr_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) +{ + return addr; /* I assume 1:1 address correspondance */ +} + +int avr_cpu_handle_mmu_fault( + CPUState *cs, vaddr address, int size, int rw, int mmu_idx) +{ + /* currently it's assumed that this will never happen */ + cs->exception_index =3D EXCP_DEBUG; + cpu_dump_state(cs, stderr, 0); + return 1; +} + +bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size, + MMUAccessType access_type, int mmu_idx, + bool probe, uintptr_t retaddr) +{ + int prot =3D 0; + MemTxAttrs attrs =3D {}; + uint32_t paddr; + + address &=3D TARGET_PAGE_MASK; + + if (mmu_idx =3D=3D MMU_CODE_IDX) { + /* access to code in flash */ + paddr =3D OFFSET_CODE + address; + prot =3D PAGE_READ | PAGE_EXEC; + if (paddr + TARGET_PAGE_SIZE > OFFSET_DATA) { + error_report("execution left flash memory"); + exit(1); + } + } else if (address < NO_CPU_REGISTERS + NO_IO_REGISTERS) { + /* + * access to CPU registers, exit and rebuilt this TB to use full a= ccess + * incase it touches specially handled registers like SREG or SP + */ + AVRCPU *cpu =3D AVR_CPU(cs); + CPUAVRState *env =3D &cpu->env; + env->fullacc =3D 1; + cpu_loop_exit_restore(cs, retaddr); + } else { + /* access to memory. nothing special */ + paddr =3D OFFSET_DATA + address; + prot =3D PAGE_READ | PAGE_WRITE; + } + + tlb_set_page_with_attrs( + cs, address, paddr, attrs, prot, mmu_idx, TARGET_PAGE_SIZE); + + return true; +} + +void helper_sleep(CPUAVRState *env) +{ + CPUState *cs =3D env_cpu(env); + + cs->exception_index =3D EXCP_HLT; + cpu_loop_exit(cs); +} + +void helper_unsupported(CPUAVRState *env) +{ + CPUState *cs =3D env_cpu(env); + + /* + * I count not find what happens on the real platform, so + * it's EXCP_DEBUG for meanwhile + */ + cs->exception_index =3D EXCP_DEBUG; + if (qemu_loglevel_mask(LOG_UNIMP)) { + qemu_log("UNSUPPORTED\n"); + cpu_dump_state(cs, qemu_logfile, 0); + } + cpu_loop_exit(cs); +} + +void helper_debug(CPUAVRState *env) +{ + CPUState *cs =3D env_cpu(env); + + cs->exception_index =3D EXCP_DEBUG; + cpu_loop_exit(cs); +} + +void helper_break(CPUAVRState *env) +{ + CPUState *cs =3D env_cpu(env); + + cs->exception_index =3D EXCP_DEBUG; + cpu_loop_exit(cs); +} + +void helper_wdr(CPUAVRState *env) +{ + CPUState *cs =3D env_cpu(env); + + /* WD is not implemented yet, placeholder */ + cs->exception_index =3D EXCP_DEBUG; + cpu_loop_exit(cs); +} + +/* + * This function implements IN instruction + * + * It does the following + * a. if an IO register belongs to CPU, its value is read and returned + * b. otherwise io address is translated to mem address and physical memo= ry + * is read. + * c. it caches the value for sake of SBI, SBIC, SBIS & CBI implementation + * + */ +target_ulong helper_inb(CPUAVRState *env, uint32_t port) +{ + target_ulong data =3D 0; + + switch (port) { + case 0x38: /* RAMPD */ + data =3D 0xff & (env->rampD >> 16); + break; + case 0x39: /* RAMPX */ + data =3D 0xff & (env->rampX >> 16); + break; + case 0x3a: /* RAMPY */ + data =3D 0xff & (env->rampY >> 16); + break; + case 0x3b: /* RAMPZ */ + data =3D 0xff & (env->rampZ >> 16); + break; + case 0x3c: /* EIND */ + data =3D 0xff & (env->eind >> 16); + break; + case 0x3d: /* SPL */ + data =3D env->sp & 0x00ff; + break; + case 0x3e: /* SPH */ + data =3D env->sp >> 8; + break; + case 0x3f: /* SREG */ + data =3D cpu_get_sreg(env); + break; + default: + /* not a special register, pass to normal memory access */ + cpu_physical_memory_read(OFFSET_IO_REGISTERS + port, &data, 1); + } + + return data; +} + +/* + * This function implements OUT instruction + * + * It does the following + * a. if an IO register belongs to CPU, its value is written into the re= gister + * b. otherwise io address is translated to mem address and physical mem= ory + * is written. + * c. it caches the value for sake of SBI, SBIC, SBIS & CBI implementati= on + * + */ +void helper_outb(CPUAVRState *env, uint32_t port, uint32_t data) +{ + data &=3D 0x000000ff; + + switch (port) { + case 0x38: /* RAMPD */ + if (avr_feature(env, AVR_FEATURE_RAMPD)) { + env->rampD =3D (data & 0xff) << 16; + } + break; + case 0x39: /* RAMPX */ + if (avr_feature(env, AVR_FEATURE_RAMPX)) { + env->rampX =3D (data & 0xff) << 16; + } + break; + case 0x3a: /* RAMPY */ + if (avr_feature(env, AVR_FEATURE_RAMPY)) { + env->rampY =3D (data & 0xff) << 16; + } + break; + case 0x3b: /* RAMPZ */ + if (avr_feature(env, AVR_FEATURE_RAMPZ)) { + env->rampZ =3D (data & 0xff) << 16; + } + break; + case 0x3c: /* EIDN */ + env->eind =3D (data & 0xff) << 16; + break; + case 0x3d: /* SPL */ + env->sp =3D (env->sp & 0xff00) | (data); + break; + case 0x3e: /* SPH */ + if (avr_feature(env, AVR_FEATURE_2_BYTE_SP)) { + env->sp =3D (env->sp & 0x00ff) | (data << 8); + } + break; + case 0x3f: /* SREG */ + cpu_set_sreg(env, data); + break; + default: + /* not a special register, pass to normal memory access */ + cpu_physical_memory_write(OFFSET_IO_REGISTERS + port, &data, 1); + } +} + +/* + * this function implements LD instruction when there is a posibility to = read + * from a CPU register + */ +target_ulong helper_fullrd(CPUAVRState *env, uint32_t addr) +{ + uint8_t data; + + env->fullacc =3D false; + + if (addr < NO_CPU_REGISTERS) { + /* CPU registers */ + data =3D env->r[addr]; + } else if (addr < NO_CPU_REGISTERS + NO_IO_REGISTERS) { + /* IO registers */ + data =3D helper_inb(env, addr - NO_CPU_REGISTERS); + } else { + /* memory */ + cpu_physical_memory_read(OFFSET_DATA + addr, &data, 1); + } + return data; +} + +/* + * this function implements ST instruction when there is a posibility to = write + * into a CPU register + */ +void helper_fullwr(CPUAVRState *env, uint32_t data, uint32_t addr) +{ + env->fullacc =3D false; + + /* Following logic assumes this: */ + assert(OFFSET_CPU_REGISTERS =3D=3D OFFSET_DATA); + assert(OFFSET_IO_REGISTERS =3D=3D OFFSET_CPU_REGISTERS + NO_CPU_REGIST= ERS); + + if (addr < NO_CPU_REGISTERS) { + /* CPU registers */ + env->r[addr] =3D data; + } else if (addr < NO_CPU_REGISTERS + NO_IO_REGISTERS) { + /* IO registers */ + helper_outb(env, addr - NO_CPU_REGISTERS, data); + } else { + /* memory */ + cpu_physical_memory_write(OFFSET_DATA + addr, &data, 1); + } +} diff --git a/target/avr/helper.h b/target/avr/helper.h new file mode 100644 index 0000000000..bf087504a8 --- /dev/null +++ b/target/avr/helper.h @@ -0,0 +1,29 @@ +/* + * QEMU AVR CPU + * + * Copyright (c) 2019 Michael Rolnik + * + * 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 + * + */ + +DEF_HELPER_1(wdr, void, env) +DEF_HELPER_1(debug, void, env) +DEF_HELPER_1(break, void, env) +DEF_HELPER_1(sleep, void, env) +DEF_HELPER_1(unsupported, void, env) +DEF_HELPER_3(outb, void, env, i32, i32) +DEF_HELPER_2(inb, tl, env, i32) +DEF_HELPER_3(fullwr, void, env, i32, i32) +DEF_HELPER_2(fullrd, tl, env, i32) --=20 2.17.2 (Apple Git-113) From nobody Tue May 7 17:09:40 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1571074112; cv=none; d=zoho.com; s=zohoarc; b=mPrSUnzkx91C64p8Txf6EIWDwdw/lwCqudiUOUBsvwvDU6UKMm/ZiqHeN+/BX6R3PVWWgNqJsxl0Ivi7cnGWE1u+6BPYNqc2lKMwE/D/MXTg4I7AjVp6e7GkleL1tKpVNomqPmmSaVtrvGPS78J+0ZI6YtS8o7M7OzUOPTvNTpM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1571074112; h=Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:Message-ID:References:Sender:Subject:To; bh=oElsIV9jGIkcznG1hjJ8A0RR90Xk82sVn+s7o2gFZVw=; b=jyXMG00RrrvCGWsnez/AkzDwaACYGN4GIkkttL0vizm9gK1WaKdTNp2Dq8gq4cY2z5xJ+qx/tL6qbZTuoEJMw52ryqRdN97E7fyLhCZ7WSGgbj0F/wqfiRRiyZqb3olo0UYfmcLVD3a9qwcw9RLsKpo1BgG64bzXTkmgxDPyX3Q= ARC-Authentication-Results: i=1; mx.zoho.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1571074112682623.6238761646408; Mon, 14 Oct 2019 10:28:32 -0700 (PDT) Received: from localhost ([::1]:54534 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iK48w-0002At-4G for importer@patchew.org; Mon, 14 Oct 2019 13:28:26 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:39782) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iK33z-00064S-Cu for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:16 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iK33x-0007N7-Ve for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:15 -0400 Received: from mail-wm1-x343.google.com ([2a00:1450:4864:20::343]:39943) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1iK33x-0007My-Ou for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:13 -0400 Received: by mail-wm1-x343.google.com with SMTP id b24so17343304wmj.5 for ; Mon, 14 Oct 2019 09:19:13 -0700 (PDT) Received: from 8c859074c0ff.ant.amazon.com.com (bzq-79-178-11-117.red.bezeqint.net. [79.178.11.117]) by smtp.gmail.com with ESMTPSA id c132sm28050861wme.27.2019.10.14.09.19.10 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 14 Oct 2019 09:19:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=oElsIV9jGIkcznG1hjJ8A0RR90Xk82sVn+s7o2gFZVw=; b=SPJy60QKyOu/5wWK/bzMAAKGhfXFW5PXCgksozOY58WD+nsCZf9zFxU9zGN+/x9OZl TQ7Z499SOYsNpmTDVcanP+BVQAr3pcOV72JvWtO+yd6Kzj7D9Tq0SEyjSYcX99fXM24k w0junZJBS5Rk8yHYXHggup42I/jDgZpYQ2p59xGZFnvggDNwwfYrNPXAC2fB7bSQzAt4 mEDtDe14SV4ljE1UCfGAbhpCv4NCuTG8UAUH7dxvR5hXsto1AoFGS+x3OydawTH6UdhD zn78ELpP7CiVyHYB+W3nsXixcIpySmOAYAwDlTe8z5BDVklXnolfbIKhAWUHhQh+m/Kr hTSA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=oElsIV9jGIkcznG1hjJ8A0RR90Xk82sVn+s7o2gFZVw=; b=sIHDK8SjQG/jbaHsXmgdf91LOhclAIVbxQU2EyELt2t64db/Y/8kFMC59A+Ix6Q63g ZX4/PW8pgwFzz4mB2Mq2371kzQ089qst5h2FNRcXQwT6UMm8kwAYBNGu0A3jefFP1Xvq 23arNso3fUYu9NAp9S80Du/lDjYQA5Q43/kFm2pDi4A1psHi+1V6FUXOWsoUOzrKtqq2 WQjONW+/0VKzX60wtscJc+4OpQfJ1UOsRVGfGHN3rAQTcaXs5OH9Rn6hCxzcBkXR3ycR HaRxOolS8NRsU4hPDyegqPTQtmo9A0Oy5NxwycGAKLXx+qi6qnNfriDcSLEkaCNU3cou imtQ== X-Gm-Message-State: APjAAAUuEWzNaLXUfcVOTottDuQVTgGvulxxYuOvKbJB9CrKgHNbaovq uKv0UMldcxgL2pCj3d/VJcWaePhr+VY= X-Google-Smtp-Source: APXvYqzZc1qNS4ADPXr2kLNmntPdFMVWE5KempNv1Fs9aL+miKN75Z6jQqKegsbG07dPJmAUYqR14Q== X-Received: by 2002:a1c:1dc9:: with SMTP id d192mr16538135wmd.51.1571069952318; Mon, 14 Oct 2019 09:19:12 -0700 (PDT) From: Michael Rolnik To: qemu-devel@nongnu.org Subject: [PATCH v32 03/13] target/avr: Add instruction decoding Date: Mon, 14 Oct 2019 19:18:33 +0300 Message-Id: <20191014161843.84845-4-mrolnik@gmail.com> X-Mailer: git-send-email 2.17.2 (Apple Git-113) In-Reply-To: <20191014161843.84845-1-mrolnik@gmail.com> References: <20191014161843.84845-1-mrolnik@gmail.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::343 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: thuth@redhat.com, Michael Rolnik , richard.henderson@linaro.org, dovgaluk@ispras.ru, imammedo@redhat.com, philmd@redhat.com, aleksandar.m.mail@gmail.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This includes: - encoding of all 16 bit instructions - encoding of all 32 bit instructions Signed-off-by: Michael Rolnik --- target/avr/insn.decode | 175 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 target/avr/insn.decode diff --git a/target/avr/insn.decode b/target/avr/insn.decode new file mode 100644 index 0000000000..6b387762c6 --- /dev/null +++ b/target/avr/insn.decode @@ -0,0 +1,175 @@ +# +# A =3D [16 .. 31] +# B =3D [16 .. 23] +# C =3D [24, 26, 28, 30] +# D =3D [0, 2, 4, 6, 8, .. 30] + +%rd 4:5 +%rr 9:1 0:4 + +&rd_rr rd rr +&rd_imm rd imm + +@op_rd_rr .... .. . ..... .... &rd_rr rd=3D%rd rr=3D%rr +ADD 0000 11 . ..... .... @op_rd_rr +ADC 0001 11 . ..... .... @op_rd_rr +AND 0010 00 . ..... .... @op_rd_rr +CP 0001 01 . ..... .... @op_rd_rr +CPC 0000 01 . ..... .... @op_rd_rr +CPSE 0001 00 . ..... .... @op_rd_rr +EOR 0010 01 . ..... .... @op_rd_rr +MOV 0010 11 . ..... .... @op_rd_rr +MUL 1001 11 . ..... .... @op_rd_rr +OR 0010 10 . ..... .... @op_rd_rr +SBC 0000 10 . ..... .... @op_rd_rr +SUB 0001 10 . ..... .... @op_rd_rr + + +%rd_c 4:2 !function=3Dto_C +%imm6 6:2 0:4 + +@op_rd_imm6 .... .... .. .. .... &rd_imm rd=3D%rd_c imm=3D%= imm6 +ADIW 1001 0110 .. .. .... @op_rd_imm6 +SBIW 1001 0111 .. .. .... @op_rd_imm6 + + +%rd_a 4:4 !function=3Dto_A +%rr_a 0:4 !function=3Dto_A +%rd_d 4:4 !function=3Dto_D +%rr_d 0:4 !function=3Dto_D +%imm8 8:4 0:4 + +@op_rd_imm8 .... .... .... .... &rd_imm rd=3D%rd_a imm=3D%= imm8 +ANDI 0111 .... .... .... @op_rd_imm8 +CPI 0011 .... .... .... @op_rd_imm8 +LDI 1110 .... .... .... @op_rd_imm8 +ORI 0110 .... .... .... @op_rd_imm8 +SBCI 0100 .... .... .... @op_rd_imm8 +SUBI 0101 .... .... .... @op_rd_imm8 + + +@op_rd .... ... rd:5 .... +ASR 1001 010 ..... 0101 @op_rd +COM 1001 010 ..... 0000 @op_rd +DEC 1001 010 ..... 1010 @op_rd +ELPM2 1001 000 ..... 0110 @op_rd +ELPMX 1001 000 ..... 0111 @op_rd +INC 1001 010 ..... 0011 @op_rd +LDX1 1001 000 ..... 1100 @op_rd +LDX2 1001 000 ..... 1101 @op_rd +LDX3 1001 000 ..... 1110 @op_rd +LDY2 1001 000 ..... 1001 @op_rd +LDY3 1001 000 ..... 1010 @op_rd +LDZ2 1001 000 ..... 0001 @op_rd +LDZ3 1001 000 ..... 0010 @op_rd +LPM2 1001 000 ..... 0100 @op_rd +LPMX 1001 000 ..... 0101 @op_rd +LSR 1001 010 ..... 0110 @op_rd +NEG 1001 010 ..... 0001 @op_rd +POP 1001 000 ..... 1111 @op_rd +PUSH 1001 001 ..... 1111 @op_rd +ROR 1001 010 ..... 0111 @op_rd +STY2 1001 001 ..... 1001 @op_rd +STY3 1001 001 ..... 1010 @op_rd +STZ2 1001 001 ..... 0001 @op_rd +STZ3 1001 001 ..... 0010 @op_rd +SWAP 1001 010 ..... 0010 @op_rd + + +@op_bit .... .... . bit:3 .... +BCLR 1001 0100 1 ... 1000 @op_bit +BSET 1001 0100 0 ... 1000 @op_bit + + +@op_rd_bit .... ... rd:5 . bit:3 +BLD 1111 100 ..... 0 ... @op_rd_bit +BST 1111 101 ..... 0 ... @op_rd_bit + + +@op_bit_imm .... .. imm:s7 bit:3 +BRBC 1111 01 ....... ... @op_bit_imm +BRBS 1111 00 ....... ... @op_bit_imm + + +BREAK 1001 0101 1001 1000 +EICALL 1001 0101 0001 1001 +EIJMP 1001 0100 0001 1001 +ELPM1 1001 0101 1101 1000 +ICALL 1001 0101 0000 1001 +IJMP 1001 0100 0000 1001 +LPM1 1001 0101 1100 1000 +NOP 0000 0000 0000 0000 +RET 1001 0101 0000 1000 +RETI 1001 0101 0001 1000 +SLEEP 1001 0101 1000 1000 +SPM 1001 0101 1110 1000 +SPMX 1001 0101 1111 1000 +WDR 1001 0101 1010 1000 + + +@op_reg_bit .... .... reg:5 bit:3 +CBI 1001 1000 ..... ... @op_reg_bit +SBI 1001 1010 ..... ... @op_reg_bit +SBIC 1001 1001 ..... ... @op_reg_bit +SBIS 1001 1011 ..... ... @op_reg_bit + + +DES 1001 0100 imm:4 1011 + + +%rd_b 4:3 !function=3Dto_B +%rr_b 0:3 !function=3Dto_B +@fmul .... .... . ... . ... &rd_rr rd=3D%rd_b rr=3D%r= r_b +FMUL 0000 0011 0 ... 1 ... @fmul +FMULS 0000 0011 1 ... 0 ... @fmul +FMULSU 0000 0011 1 ... 1 ... @fmul +MULSU 0000 0011 0 ... 0 ... @fmul + + +%io_imm 9:2 0:4 +@io_rd_imm .... . .. ..... .... &rd_imm rd=3D%rd imm=3D%io= _imm +IN 1011 0 .. ..... .... @io_rd_imm +OUT 1011 1 .. ..... .... @io_rd_imm + + +XCH 1001 001 rd:5 0100 +LAC 1001 001 rd:5 0110 +LAS 1001 001 rd:5 0101 +LAT 1001 001 rd:5 0111 +STX1 1001 001 rr:5 1100 +STX2 1001 001 rr:5 1101 +STX3 1001 001 rr:5 1110 + + +%ldst_d_imm 13:1 10:2 0:3 +@ldst_d .. . . .. . rd:5 . ... &rd_imm imm=3D%ldst_d_imm +LDDY 10 . 0 .. 0 ..... 1 ... @ldst_d +LDDZ 10 . 0 .. 0 ..... 0 ... @ldst_d +STDY 10 . 0 .. 1 ..... 1 ... @ldst_d +STDZ 10 . 0 .. 1 ..... 0 ... @ldst_d + + +MOVW 0000 0001 .... .... &rd_rr rd=3D%rd_d rr=3D%r= r_d +MULS 0000 0010 .... .... &rd_rr rd=3D%rd_a rr=3D%r= r_a + +RCALL 1101 imm:s12 +RJMP 1100 imm:s12 + +SBRC 1111 110 rr:5 0 bit:3 +SBRS 1111 111 rr:5 0 bit:3 + +# The 22-bit immediate is partially in the opcode word, +# and partially in the next. Use append_16 to build the +# complete 22-bit value. +%imm_call 4:5 0:1 !function=3Dappend_16 +CALL 1001 010 ..... 111 . imm=3D%imm_call +JMP 1001 010 ..... 110 . imm=3D%imm_call + + +# The 16-bit immediate is completely in the next word. +# Fields cannot be defined with no bits, so we cannot play +# the same trick and append to a zero-bit value. +# Defer reading the immediate until trans_{LDS,STS}. +@ldst_s .... ... rd:5 .... imm=3D0 +LDS 1001 000 ..... 0000 @ldst_s +STS 1001 001 ..... 0000 @ldst_s --=20 2.17.2 (Apple Git-113) From nobody Tue May 7 17:09:40 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1571074707; cv=none; d=zoho.com; s=zohoarc; b=j5AO/Qpw2oJWXBixW3bdeReW71di7krk+jiAn5ZePxpoyc7hpk861mAN52RUdhn2tLUJhKzIcH8ZooOPWZ4gH33ikF8yBERDh+xyzvuY/DFwL9+2uSOtbyO8E8vPerhwF8LJR9sJHLNVSYeEUQPcOu+WSZ2hZRNoUNKsinaEVAY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1571074707; h=Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:Message-ID:References:Sender:Subject:To; bh=sXgUfb/k+VBdpZH8pPaVua4ZrgGvG7BUVKKWHWPW/NE=; b=EAJiMcT2qAkkrWETHiyg59OmWaNvGkoWnivIORlhL8I3d3guck2M07G76pNuKmRCma1UZ+AA6WbkQ85olKaXRsuAwl8Ow5SfhxYIatmtN4Goe5BM/6HM780ebqALwMUyafjT5zGCMubgRQaA2J9hbDtFw/ZxqqBm3GvYrukivPE= ARC-Authentication-Results: i=1; mx.zoho.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1571074707431405.96118283435476; Mon, 14 Oct 2019 10:38:27 -0700 (PDT) Received: from localhost ([::1]:54732 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iK4Ic-0006c0-6L for importer@patchew.org; Mon, 14 Oct 2019 13:38:26 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:39797) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iK341-00066g-3L for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:18 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iK33z-0007Q7-Jg for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:16 -0400 Received: from mail-wm1-x32b.google.com ([2a00:1450:4864:20::32b]:52348) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1iK33z-0007Ni-D9 for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:15 -0400 Received: by mail-wm1-x32b.google.com with SMTP id r19so17909924wmh.2 for ; Mon, 14 Oct 2019 09:19:15 -0700 (PDT) Received: from 8c859074c0ff.ant.amazon.com.com (bzq-79-178-11-117.red.bezeqint.net. [79.178.11.117]) by smtp.gmail.com with ESMTPSA id c132sm28050861wme.27.2019.10.14.09.19.12 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 14 Oct 2019 09:19:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=sXgUfb/k+VBdpZH8pPaVua4ZrgGvG7BUVKKWHWPW/NE=; b=JUPLVSpsgEE+OgheW5LhIBeKF6UFFnnl53MfhBfdz+BMpEwzk8tnWWjVa1m6wslPI4 bBrJClO596Uef53U1imqZo0F39mi5BauSfUm3vfdaSz0dplG8sxTFqqny4lUi0FozF4L HpeIlhnMdl83TmEDG//rs5VgW3p1i9ZAJPFFbCPQxUcfBAfGY7pLn7nDD6sw71Zm0m9L ezOPp32Iup6QBLzI8YevXRGFUp9I2yz+GRBQIdyI/lqWRwZwBaupeJBCOtSbybuHUEol CqtnMX+FPz4cutj7mqvg+HUF08cinutlH3QlMW6ny4a+XENk96Ziaj6sbrrusCI69Hsf fQUg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=sXgUfb/k+VBdpZH8pPaVua4ZrgGvG7BUVKKWHWPW/NE=; b=csZMbghcnL+GcruNC1bXjGlCMJUomyD0n6wOb+92ly/FvE7tEsF9NGfcgLH2/4maYx v4ujC/WUd+K8pU7Bgwsq7LJbcPkzdvtFnJ+oD5TiJce5odcz6Z5bgp4nZ06gdukH/5Hp 40GYhkI/gyx1v+mVwO3m1x60tb1GzLvM+RJFyo2Lfbb0+nyGFAl4jQ4Daz15nTbP01ZY nbC1T7ISyd648H6qJw3OASM+txofLpf5rLc7hY2fAxDeSxQohFmpw9Pf/7BdgyV2Kohq E6xt9lJfooqHbK2G6O92GxY2QrrfDyYRXw+KoIRTomFBEfjthCcucPdeibylPxBbxyQK EO3g== X-Gm-Message-State: APjAAAUCb98drqJqqwtdAvlabS6Mj/Mmw/CeSGuE6OD5xxACjTInCy+T 17yVnaXmaLtOXG1u87cKnPYruouxhaQ= X-Google-Smtp-Source: APXvYqzkeAa+lNKrlZbr1ePgVEdRTHrUhbOlLQX5xtC3LlH6Gk3sp81Ad8l1qajK9y4H5nbci/88TQ== X-Received: by 2002:a1c:8157:: with SMTP id c84mr15297439wmd.56.1571069953902; Mon, 14 Oct 2019 09:19:13 -0700 (PDT) From: Michael Rolnik To: qemu-devel@nongnu.org Subject: [PATCH v32 04/13] target/avr: Add instruction translation - Registers definition Date: Mon, 14 Oct 2019 19:18:34 +0300 Message-Id: <20191014161843.84845-5-mrolnik@gmail.com> X-Mailer: git-send-email 2.17.2 (Apple Git-113) In-Reply-To: <20191014161843.84845-1-mrolnik@gmail.com> References: <20191014161843.84845-1-mrolnik@gmail.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::32b X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: thuth@redhat.com, Michael Rolnik , richard.henderson@linaro.org, dovgaluk@ispras.ru, imammedo@redhat.com, philmd@redhat.com, aleksandar.m.mail@gmail.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Signed-off-by: Michael Rolnik --- target/avr/translate.c | 132 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 target/avr/translate.c diff --git a/target/avr/translate.c b/target/avr/translate.c new file mode 100644 index 0000000000..53c9892a60 --- /dev/null +++ b/target/avr/translate.c @@ -0,0 +1,132 @@ +/* + * QEMU AVR CPU + * + * Copyright (c) 2019 Michael Rolnik + * + * 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 + * + */ + +#include "qemu/osdep.h" +#include "qemu/qemu-print.h" +#include "tcg/tcg.h" +#include "cpu.h" +#include "exec/exec-all.h" +#include "disas/disas.h" +#include "tcg-op.h" +#include "exec/cpu_ldst.h" +#include "exec/helper-proto.h" +#include "exec/helper-gen.h" +#include "exec/log.h" +#include "exec/gdbstub.h" +#include "exec/translator.h" +#include "exec/gen-icount.h" + +/* + * Define if you want a BREAK instruction translated to a breakpoint + * Active debugging connection is assumed + * This is for + * https://github.com/seharris/qemu-avr-tests/tree/master/instruction-tes= ts + * tests + */ +#undef BREAKPOINT_ON_BREAK + +static TCGv cpu_pc; + +static TCGv cpu_Cf; +static TCGv cpu_Zf; +static TCGv cpu_Nf; +static TCGv cpu_Vf; +static TCGv cpu_Sf; +static TCGv cpu_Hf; +static TCGv cpu_Tf; +static TCGv cpu_If; + +static TCGv cpu_rampD; +static TCGv cpu_rampX; +static TCGv cpu_rampY; +static TCGv cpu_rampZ; + +static TCGv cpu_r[NO_CPU_REGISTERS]; +static TCGv cpu_eind; +static TCGv cpu_sp; + +static TCGv cpu_skip; + +static const char reg_names[NO_CPU_REGISTERS][8] =3D { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", +}; +#define REG(x) (cpu_r[x]) + +enum { + DISAS_EXIT =3D DISAS_TARGET_0, /* We want return to the cpu main lo= op. */ + DISAS_LOOKUP =3D DISAS_TARGET_1, /* We have a variable condition exit= . */ + DISAS_CHAIN =3D DISAS_TARGET_2, /* We have a single condition exit. = */ +}; + +typedef struct DisasContext DisasContext; + +/* This is the state at translation time. */ +struct DisasContext { + TranslationBlock *tb; + + CPUAVRState *env; + CPUState *cs; + + target_long npc; + uint32_t opcode; + + /* Routine used to access memory */ + int memidx; + int bstate; + int singlestep; + + TCGv skip_var0; + TCGv skip_var1; + TCGCond skip_cond; + bool free_skip_var0; +}; + +static int to_A(DisasContext *ctx, int indx) { return 16 + (indx % 16); } +static int to_B(DisasContext *ctx, int indx) { return 16 + (indx % 8); } +static int to_C(DisasContext *ctx, int indx) { return 24 + (indx % 4) * 2;= } +static int to_D(DisasContext *ctx, int indx) { return (indx % 16) * 2; } + +static uint16_t next_word(DisasContext *ctx) +{ + return cpu_lduw_code(ctx->env, ctx->npc++ * 2); +} + +static int append_16(DisasContext *ctx, int x) +{ + return x << 16 | next_word(ctx); +} + + +static bool avr_have_feature(DisasContext *ctx, int feature) +{ + if (!avr_feature(ctx->env, feature)) { + gen_helper_unsupported(cpu_env); + ctx->bstate =3D DISAS_NORETURN; + return false; + } + return true; +} + +static bool decode_insn(DisasContext *ctx, uint16_t insn); +#include "decode_insn.inc.c" + --=20 2.17.2 (Apple Git-113) From nobody Tue May 7 17:09:40 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1571074872; cv=none; d=zoho.com; s=zohoarc; b=KRI7FHJ2D+VSITV6+27ipFdJC2NNhk9ZltvK1P4X9EFFfG+0+N87MQY3YyZ6d2XkEahpiG7qOc+84Rqznqc06uTEYehRH/4kS85NuCF1OGo8WkhIJVwWSbdlf2RBmXnr4epCHdSeoo8PFZGaYS6GN/l0LdeU3NgCjG/T/67OXHk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1571074872; h=Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:Message-ID:References:Sender:Subject:To; bh=S7FJ2505Jp12axStf1KKkSUlLAApAhBZpbBFHcR/OqI=; b=nDSKHsAOUYMPy9XXl1E5xoOHttOyKmibr155Tyei2/qD0vLzhHcVUyw8NuVE3u3UJCTyEz22smd3xsXAIAOjjcmIxrBgEDvTZRL5DdB0EG3l/g0nhjmKEaNm1wIN8Z7xpLHeoKKxSnem7De4qDHXhQZq5B29h8nIgYIWvmNPk90= ARC-Authentication-Results: i=1; mx.zoho.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (209.51.188.17 [209.51.188.17]) by mx.zohomail.com with SMTPS id 1571074872557655.9610235165358; Mon, 14 Oct 2019 10:41:12 -0700 (PDT) Received: from localhost ([::1]:54766 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iK4LC-0000Sx-4b for importer@patchew.org; Mon, 14 Oct 2019 13:41:06 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:39815) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iK344-0006CL-OI for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:23 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iK342-0007T1-0H for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:20 -0400 Received: from mail-wr1-x443.google.com ([2a00:1450:4864:20::443]:35936) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1iK341-0007Rm-NU for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:17 -0400 Received: by mail-wr1-x443.google.com with SMTP id y19so20453361wrd.3 for ; Mon, 14 Oct 2019 09:19:17 -0700 (PDT) Received: from 8c859074c0ff.ant.amazon.com.com (bzq-79-178-11-117.red.bezeqint.net. [79.178.11.117]) by smtp.gmail.com with ESMTPSA id c132sm28050861wme.27.2019.10.14.09.19.13 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 14 Oct 2019 09:19:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=S7FJ2505Jp12axStf1KKkSUlLAApAhBZpbBFHcR/OqI=; b=J/FGaykm3vR+BbIVJAIH0zBukQTKUuqz3cj7uqzDFxqUOEIjGEcxYTfvAXxr9RIcs+ sOQdUyrTba9E7n4FhmNyn924GADK3tJWiXJeDbjH9lItlbuH8Fg4fLVEO1FOkPI0RfOg kQ23wkNqB74oWYFM6PlquPOV9rPowm7QN0j6o1vif79u1dG3YF//jKJCDRvk+iRI+aIp uiEmmtU6qgr4LcyabfYL0XcPuD3wrRS12I3i3NZv3KkMWpBhh1mU5anl1tX/MCQ5uRd1 exNZY5F+2bkpPR4x2lgU+xnr9iBYS6SD/t7/IDQuDKIBG9a9K6a/CxVvbzvKS6CSSl5L pZBA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=S7FJ2505Jp12axStf1KKkSUlLAApAhBZpbBFHcR/OqI=; b=c+6ajTfoVHn9cVIOUPsKGomFtwqYGw3XINOb8dDfKtRpEB+SmyWkrR70QfRbWvejIN qEbwydPGoK44IQPLZzHqUS+MiaQGAVwzA5TtTZzZKjs+K3l0rS+1q6AUinFVLCDCA4ng tyQ6/SxyZhhwfpD7w7ZIv97CExFPQ9boJUXsZDYk3ARdmfKokhWbTWumScIWdmtfHv+u jcnzYk/jmRKtCvwCAYtXfVOD0hMtJd0By5Q+ANhkt5SYGlaPXIG5c5/bj9MV5Gf36M4Y c4qZacIYw1FmAkcHkWnbxDUCI5E4sEQ2jsKtRkmY4fykXNO+zGmLPwOOyerwfodFXWBZ f2qg== X-Gm-Message-State: APjAAAWUEyO/6uTV3lR93D1fIb1Vi9QPcjhlIXpQq7CG8a9p/VJbSt8d JOQDMnN+ytg0QnP7/059PnSFmrzsvWg= X-Google-Smtp-Source: APXvYqzmt0nNugUmb58lFqibaOi470a6bq5RSREGYsLjgd0AtZJwUNSCgC88BqPy9eI/dnO++URZNQ== X-Received: by 2002:adf:dfc6:: with SMTP id q6mr26769683wrn.207.1571069955950; Mon, 14 Oct 2019 09:19:15 -0700 (PDT) From: Michael Rolnik To: qemu-devel@nongnu.org Subject: [PATCH v32 05/13] target/avr: Add instruction translation - Arithmetic and Logic Instructions Date: Mon, 14 Oct 2019 19:18:35 +0300 Message-Id: <20191014161843.84845-6-mrolnik@gmail.com> X-Mailer: git-send-email 2.17.2 (Apple Git-113) In-Reply-To: <20191014161843.84845-1-mrolnik@gmail.com> References: <20191014161843.84845-1-mrolnik@gmail.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::443 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: thuth@redhat.com, Michael Rolnik , richard.henderson@linaro.org, dovgaluk@ispras.ru, imammedo@redhat.com, philmd@redhat.com, aleksandar.m.mail@gmail.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This includes: - ADD, ADC, ADIW Signed-off-by: Michael Rolnik --- target/avr/translate.c | 811 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 811 insertions(+) diff --git a/target/avr/translate.c b/target/avr/translate.c index 53c9892a60..3eaa3e5099 100644 --- a/target/avr/translate.c +++ b/target/avr/translate.c @@ -130,3 +130,814 @@ static bool avr_have_feature(DisasContext *ctx, int f= eature) static bool decode_insn(DisasContext *ctx, uint16_t insn); #include "decode_insn.inc.c" =20 + +static void gen_add_CHf(TCGv R, TCGv Rd, TCGv Rr) +{ + TCGv t1 =3D tcg_temp_new_i32(); + TCGv t2 =3D tcg_temp_new_i32(); + TCGv t3 =3D tcg_temp_new_i32(); + + tcg_gen_and_tl(t1, Rd, Rr); /* t1 =3D Rd & Rr */ + tcg_gen_andc_tl(t2, Rd, R); /* t2 =3D Rd & ~R */ + tcg_gen_andc_tl(t3, Rr, R); /* t3 =3D Rr & ~R */ + tcg_gen_or_tl(t1, t1, t2); /* t1 =3D t1 | t2 | t3 */ + tcg_gen_or_tl(t1, t1, t3); + + tcg_gen_shri_tl(cpu_Cf, t1, 7); /* Cf =3D t1(7) */ + tcg_gen_shri_tl(cpu_Hf, t1, 3); /* Hf =3D t1(3) */ + tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1); + + tcg_temp_free_i32(t3); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t1); +} + + +static void gen_add_Vf(TCGv R, TCGv Rd, TCGv Rr) +{ + TCGv t1 =3D tcg_temp_new_i32(); + TCGv t2 =3D tcg_temp_new_i32(); + + /* t1 =3D Rd & Rr & ~R | ~Rd & ~Rr & R =3D (Rd ^ R) & ~(Rd ^ Rr) */ + tcg_gen_xor_tl(t1, Rd, R); + tcg_gen_xor_tl(t2, Rd, Rr); + tcg_gen_andc_tl(t1, t1, t2); + + tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf =3D t1(7) */ + + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t1); +} + + +static void gen_sub_CHf(TCGv R, TCGv Rd, TCGv Rr) +{ + TCGv t1 =3D tcg_temp_new_i32(); + TCGv t2 =3D tcg_temp_new_i32(); + TCGv t3 =3D tcg_temp_new_i32(); + + /* Cf & Hf */ + tcg_gen_not_tl(t1, Rd); /* t1 =3D ~Rd */ + tcg_gen_and_tl(t2, t1, Rr); /* t2 =3D ~Rd & Rr */ + tcg_gen_or_tl(t3, t1, Rr); /* t3 =3D (~Rd | Rr) & R */ + tcg_gen_and_tl(t3, t3, R); + tcg_gen_or_tl(t2, t2, t3); /* t2 =3D ~Rd & Rr | ~Rd & R | R & Rr */ + tcg_gen_shri_tl(cpu_Cf, t2, 7); /* Cf =3D t2(7) */ + tcg_gen_shri_tl(cpu_Hf, t2, 3); /* Hf =3D t2(3) */ + tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1); + + tcg_temp_free_i32(t3); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t1); +} + + +static void gen_sub_Vf(TCGv R, TCGv Rd, TCGv Rr) +{ + TCGv t1 =3D tcg_temp_new_i32(); + TCGv t2 =3D tcg_temp_new_i32(); + + /* Vf */ + /* t1 =3D Rd & ~Rr & ~R | ~Rd & Rr & R =3D (Rd ^ R) & (Rd ^ R) */ + tcg_gen_xor_tl(t1, Rd, R); + tcg_gen_xor_tl(t2, Rd, Rr); + tcg_gen_and_tl(t1, t1, t2); + tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf =3D t1(7) */ + + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t1); +} + + +static void gen_NSf(TCGv R) +{ + tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf =3D R(7) */ + tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf =3D Nf ^ Vf */ +} + + +static void gen_ZNSf(TCGv R) +{ + tcg_gen_mov_tl(cpu_Zf, R); /* Zf =3D R */ + tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf =3D R(7) */ + tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf =3D Nf ^ Vf */ +} + + +/* + * Adds two registers without the C Flag and places the result in the + * destination register Rd. + */ +static bool trans_ADD(DisasContext *ctx, arg_ADD *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv Rr =3D cpu_r[a->rr]; + TCGv R =3D tcg_temp_new_i32(); + + /* op */ + tcg_gen_add_tl(R, Rd, Rr); /* Rd =3D Rd + Rr */ + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + gen_add_CHf(R, Rd, Rr); + gen_add_Vf(R, Rd, Rr); + gen_ZNSf(R); + + /* R */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(R); + + return true; +} + + +/* + * Adds two registers and the contents of the C Flag and places the resul= t in + * the destination register Rd. + */ +static bool trans_ADC(DisasContext *ctx, arg_ADC *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv Rr =3D cpu_r[a->rr]; + TCGv R =3D tcg_temp_new_i32(); + + /* op */ + tcg_gen_add_tl(R, Rd, Rr); /* R =3D Rd + Rr + Cf */ + tcg_gen_add_tl(R, R, cpu_Cf); + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + gen_add_CHf(R, Rd, Rr); + gen_add_Vf(R, Rd, Rr); + gen_ZNSf(R); + + /* R */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(R); + + return true; +} + + +/* + * Subtracts an immediate value (0-63) from a register pair and places the + * result in the register pair. This instruction operates on the upper fo= ur + * register pairs, and is well suited for operations on the Pointer Regis= ters. + * This instruction is not available in all devices. Refer to the device + * specific instruction set summary. + */ +static bool trans_SBIW(DisasContext *ctx, arg_SBIW *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_ADIW_SBIW)) { + return true; + } + + TCGv RdL =3D cpu_r[a->rd]; + TCGv RdH =3D cpu_r[a->rd + 1]; + int Imm =3D (a->imm); + TCGv R =3D tcg_temp_new_i32(); + TCGv Rd =3D tcg_temp_new_i32(); + + /* op */ + tcg_gen_deposit_tl(Rd, RdL, RdH, 8, 8); /* Rd =3D RdH:RdL */ + tcg_gen_subi_tl(R, Rd, Imm); /* R =3D Rd - Imm */ + tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ + + /* Cf */ + tcg_gen_andc_tl(cpu_Cf, R, Rd); + tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15); /* Cf =3D R & ~Rd */ + + /* Vf */ + tcg_gen_andc_tl(cpu_Vf, Rd, R); + tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15); /* Vf =3D Rd & ~R */ + + /* Zf */ + tcg_gen_mov_tl(cpu_Zf, R); /* Zf =3D R */ + + /* Nf */ + tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf =3D R(15) */ + + /* Sf */ + tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf =3D Nf ^ Vf */ + + /* R */ + tcg_gen_andi_tl(RdL, R, 0xff); + tcg_gen_shri_tl(RdH, R, 8); + + tcg_temp_free_i32(Rd); + tcg_temp_free_i32(R); + + return true; +} + + +/* + * Adds an immediate value (0 - 63) to a register pair and places the res= ult + * in the register pair. This instruction operates on the upper four regi= ster + * pairs, and is well suited for operations on the pointer registers. Th= is + * instruction is not available in all devices. Refer to the device speci= fic + * instruction set summary. + */ +static bool trans_ADIW(DisasContext *ctx, arg_ADIW *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_ADIW_SBIW)) { + return true; + } + + TCGv RdL =3D cpu_r[a->rd]; + TCGv RdH =3D cpu_r[a->rd + 1]; + int Imm =3D (a->imm); + TCGv R =3D tcg_temp_new_i32(); + TCGv Rd =3D tcg_temp_new_i32(); + + /* op */ + tcg_gen_deposit_tl(Rd, RdL, RdH, 8, 8); /* Rd =3D RdH:RdL */ + tcg_gen_addi_tl(R, Rd, Imm); /* R =3D Rd + Imm */ + tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ + + /* Cf */ + tcg_gen_andc_tl(cpu_Cf, Rd, R); /* Cf =3D Rd & ~R */ + tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15); + + /* Vf */ + tcg_gen_andc_tl(cpu_Vf, R, Rd); /* Vf =3D R & ~Rd */ + tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15); + + /* Zf */ + tcg_gen_mov_tl(cpu_Zf, R); /* Zf =3D R */ + + /* Nf */ + tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf =3D R(15) */ + + /* Sf */ + tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf);/* Sf =3D Nf ^ Vf */ + + /* R */ + tcg_gen_andi_tl(RdL, R, 0xff); + tcg_gen_shri_tl(RdH, R, 8); + + tcg_temp_free_i32(Rd); + tcg_temp_free_i32(R); + + return true; +} + + +/* + * Subtracts two registers and places the result in the destination + * register Rd. + */ +static bool trans_SUB(DisasContext *ctx, arg_SUB *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv Rr =3D cpu_r[a->rr]; + TCGv R =3D tcg_temp_new_i32(); + + /* op */ + tcg_gen_sub_tl(R, Rd, Rr); /* R =3D Rd - Rr */ + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + gen_sub_CHf(R, Rd, Rr); + gen_sub_Vf(R, Rd, Rr); + gen_ZNSf(R); + + /* R */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(R); + + return true; +} + +/* + * Subtracts a register and a constant and places the result in the + * destination register Rd. This instruction is working on Register R16 t= o R31 + * and is very well suited for operations on the X, Y, and Z-pointers. + */ +static bool trans_SUBI(DisasContext *ctx, arg_SUBI *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv Rr =3D tcg_const_i32(a->imm); + TCGv R =3D tcg_temp_new_i32(); + + /* op */ + tcg_gen_sub_tl(R, Rd, Rr); /* R =3D Rd - Imm */ + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + gen_sub_CHf(R, Rd, Rr); + gen_sub_Vf(R, Rd, Rr); + gen_ZNSf(R); + + /* R */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(R); + tcg_temp_free_i32(Rr); + + return true; +} + + +/* + * Subtracts two registers and subtracts with the C Flag and places the + * result in the destination register Rd. + */ +static bool trans_SBC(DisasContext *ctx, arg_SBC *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv Rr =3D cpu_r[a->rr]; + TCGv R =3D tcg_temp_new_i32(); + + /* op */ + tcg_gen_sub_tl(R, Rd, Rr); /* R =3D Rd - Rr - Cf */ + tcg_gen_sub_tl(R, R, cpu_Cf); + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + gen_sub_CHf(R, Rd, Rr); + gen_sub_Vf(R, Rd, Rr); + gen_NSf(R); + + /* + * Previous value remains unchanged when the result is zero; + * cleared otherwise. + */ + tcg_gen_or_tl(cpu_Zf, cpu_Zf, R); + + /* R */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(R); + + return true; +} + + +/* + * SBCI -- Subtract Immediate with Carry + */ +static bool trans_SBCI(DisasContext *ctx, arg_SBCI *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv Rr =3D tcg_const_i32(a->imm); + TCGv R =3D tcg_temp_new_i32(); + + /* op */ + tcg_gen_sub_tl(R, Rd, Rr); /* R =3D Rd - Rr - Cf */ + tcg_gen_sub_tl(R, R, cpu_Cf); + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + gen_sub_CHf(R, Rd, Rr); + gen_sub_Vf(R, Rd, Rr); + gen_NSf(R); + + /* + * Previous value remains unchanged when the result is zero; + * cleared otherwise. + */ + tcg_gen_or_tl(cpu_Zf, cpu_Zf, R); + + /* R */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(R); + tcg_temp_free_i32(Rr); + + return true; +} + + +/* + * Performs the logical AND between the contents of register Rd and regis= ter + * Rr and places the result in the destination register Rd. + */ +static bool trans_AND(DisasContext *ctx, arg_AND *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv Rr =3D cpu_r[a->rr]; + TCGv R =3D tcg_temp_new_i32(); + + /* op */ + tcg_gen_and_tl(R, Rd, Rr); /* Rd =3D Rd and Rr */ + + /* Vf */ + tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf =3D 0 */ + + /* Zf */ + tcg_gen_mov_tl(cpu_Zf, R); /* Zf =3D R */ + + gen_ZNSf(R); + + /* R */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(R); + + return true; +} + + +/* + * Performs the logical AND between the contents of register Rd and a con= stant + * and places the result in the destination register Rd. + */ +static bool trans_ANDI(DisasContext *ctx, arg_ANDI *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + int Imm =3D (a->imm); + + /* op */ + tcg_gen_andi_tl(Rd, Rd, Imm); /* Rd =3D Rd & Imm */ + + tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf =3D 0 */ + gen_ZNSf(Rd); + + return true; +} + + +/* + * Performs the logical OR between the contents of register Rd and regist= er + * Rr and places the result in the destination register Rd. + */ +static bool trans_OR(DisasContext *ctx, arg_OR *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv Rr =3D cpu_r[a->rr]; + TCGv R =3D tcg_temp_new_i32(); + + tcg_gen_or_tl(R, Rd, Rr); + + tcg_gen_movi_tl(cpu_Vf, 0); + gen_ZNSf(R); + + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(R); + + return true; +} + + +/* + * Performs the logical OR between the contents of register Rd and a + * constant and places the result in the destination register Rd. + */ +static bool trans_ORI(DisasContext *ctx, arg_ORI *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + int Imm =3D (a->imm); + + tcg_gen_ori_tl(Rd, Rd, Imm); /* Rd =3D Rd | Imm */ + + tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf =3D 0 */ + gen_ZNSf(Rd); + + return true; +} + + +/* + * Performs the logical EOR between the contents of register Rd and + * register Rr and places the result in the destination register Rd. + */ +static bool trans_EOR(DisasContext *ctx, arg_EOR *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv Rr =3D cpu_r[a->rr]; + + tcg_gen_xor_tl(Rd, Rd, Rr); + + tcg_gen_movi_tl(cpu_Vf, 0); + gen_ZNSf(Rd); + + return true; +} + + +/* + * Clears the specified bits in register Rd. Performs the logical AND + * between the contents of register Rd and the complement of the constant= mask + * K. The result will be placed in register Rd. + */ +static bool trans_COM(DisasContext *ctx, arg_COM *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv R =3D tcg_temp_new_i32(); + + tcg_gen_xori_tl(Rd, Rd, 0xff); + + tcg_gen_movi_tl(cpu_Cf, 1); /* Cf =3D 1 */ + tcg_gen_movi_tl(cpu_Vf, 0); /* Vf =3D 0 */ + gen_ZNSf(Rd); + + tcg_temp_free_i32(R); + + return true; +} + + +/* + * Replaces the contents of register Rd with its two's complement; the + * value $80 is left unchanged. + */ +static bool trans_NEG(DisasContext *ctx, arg_NEG *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv t0 =3D tcg_const_i32(0); + TCGv R =3D tcg_temp_new_i32(); + + /* op */ + tcg_gen_sub_tl(R, t0, Rd); /* R =3D 0 - Rd */ + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + gen_sub_CHf(R, t0, Rd); + gen_sub_Vf(R, t0, Rd); + gen_ZNSf(R); + + /* R */ + tcg_gen_mov_tl(Rd, R); + + tcg_temp_free_i32(t0); + tcg_temp_free_i32(R); + + return true; +} + + +/* + * Adds one -1- to the contents of register Rd and places the result in t= he + * destination register Rd. The C Flag in SREG is not affected by the + * operation, thus allowing the INC instruction to be used on a loop coun= ter in + * multiple-precision computations. When operating on unsigned numbers, = only + * BREQ and BRNE branches can be expected to perform consistently. When + * operating on two's complement values, all signed branches are availabl= e. + */ +static bool trans_INC(DisasContext *ctx, arg_INC *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + + tcg_gen_addi_tl(Rd, Rd, 1); + tcg_gen_andi_tl(Rd, Rd, 0xff); + + /* cpu_Vf =3D Rd =3D=3D 0x80 */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x80); + gen_ZNSf(Rd); + + return true; +} + + +/* + * Subtracts one -1- from the contents of register Rd and places the resu= lt + * in the destination register Rd. The C Flag in SREG is not affected by= the + * operation, thus allowing the DEC instruction to be used on a loop coun= ter in + * multiple-precision computations. When operating on unsigned values, o= nly + * BREQ and BRNE branches can be expected to perform consistently. When + * operating on two's complement values, all signed branches are availabl= e. + */ +static bool trans_DEC(DisasContext *ctx, arg_DEC *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + + tcg_gen_subi_tl(Rd, Rd, 1); /* Rd =3D Rd - 1 */ + tcg_gen_andi_tl(Rd, Rd, 0xff); /* make it 8 bits */ + + /* cpu_Vf =3D Rd =3D=3D 0x7f */ + tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x7f); + gen_ZNSf(Rd); + + return true; +} + + +/* + * This instruction performs 8-bit x 8-bit -> 16-bit unsigned multiplicat= ion. + */ +static bool trans_MUL(DisasContext *ctx, arg_MUL *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { + return true; + } + + TCGv R0 =3D cpu_r[0]; + TCGv R1 =3D cpu_r[1]; + TCGv Rd =3D cpu_r[a->rd]; + TCGv Rr =3D cpu_r[a->rr]; + TCGv R =3D tcg_temp_new_i32(); + + tcg_gen_mul_tl(R, Rd, Rr); /* R =3D Rd *Rr */ + + tcg_gen_andi_tl(R0, R, 0xff); + tcg_gen_shri_tl(R1, R, 8); + + tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf =3D R(16) */ + tcg_gen_mov_tl(cpu_Zf, R); + + tcg_temp_free_i32(R); + + return true; +} + + +/* + * This instruction performs 8-bit x 8-bit -> 16-bit signed multiplicatio= n. + */ +static bool trans_MULS(DisasContext *ctx, arg_MULS *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { + return true; + } + + TCGv R0 =3D cpu_r[0]; + TCGv R1 =3D cpu_r[1]; + TCGv Rd =3D cpu_r[a->rd]; + TCGv Rr =3D cpu_r[a->rr]; + TCGv R =3D tcg_temp_new_i32(); + TCGv t0 =3D tcg_temp_new_i32(); + TCGv t1 =3D tcg_temp_new_i32(); + + tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */ + tcg_gen_ext8s_tl(t1, Rr); /* make Rr full 32 bit signed */ + tcg_gen_mul_tl(R, t0, t1); /* R =3D Rd * Rr */ + + tcg_gen_andi_tl(R0, R, 0xff); + tcg_gen_shri_tl(R1, R, 8); + + tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf =3D R(16) */ + tcg_gen_mov_tl(cpu_Zf, R); + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(R); + + return true; +} + + +/* + * This instruction performs 8-bit x 8-bit -> 16-bit multiplication of a + * signed and an unsigned number. + */ +static bool trans_MULSU(DisasContext *ctx, arg_MULSU *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { + return true; + } + + TCGv R0 =3D cpu_r[0]; + TCGv R1 =3D cpu_r[1]; + TCGv Rd =3D cpu_r[a->rd]; + TCGv Rr =3D cpu_r[a->rr]; + TCGv R =3D tcg_temp_new_i32(); + TCGv t0 =3D tcg_temp_new_i32(); + + tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */ + tcg_gen_mul_tl(R, t0, Rr); /* R =3D Rd *Rr */ + + tcg_gen_andi_tl(R0, R, 0xff); + tcg_gen_shri_tl(R1, R, 8); + + tcg_gen_shri_tl(cpu_Cf, R, 16); /* Cf =3D R(16) */ + tcg_gen_mov_tl(cpu_Zf, R); + + tcg_temp_free_i32(t0); + tcg_temp_free_i32(R); + + return true; +} + + +/* + * This instruction performs 8-bit x 8-bit -> 16-bit unsigned + * multiplication and shifts the result one bit left. + */ +static bool trans_FMUL(DisasContext *ctx, arg_FMUL *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { + return true; + } + + TCGv R0 =3D cpu_r[0]; + TCGv R1 =3D cpu_r[1]; + TCGv Rd =3D cpu_r[a->rd]; + TCGv Rr =3D cpu_r[a->rr]; + TCGv R =3D tcg_temp_new_i32(); + + tcg_gen_mul_tl(R, Rd, Rr); /* R =3D Rd *Rr */ + tcg_gen_shli_tl(R, R, 1); + + tcg_gen_andi_tl(R0, R, 0xff); + tcg_gen_shri_tl(R1, R, 8); + tcg_gen_andi_tl(R1, R1, 0xff); + + tcg_gen_shri_tl(cpu_Cf, R, 16); /* Cf =3D R(16) */ + tcg_gen_andi_tl(cpu_Zf, R, 0x0000ffff); + + tcg_temp_free_i32(R); + + return true; +} + + +/* + * This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication + * and shifts the result one bit left. + */ +static bool trans_FMULS(DisasContext *ctx, arg_FMULS *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { + return true; + } + + TCGv R0 =3D cpu_r[0]; + TCGv R1 =3D cpu_r[1]; + TCGv Rd =3D cpu_r[a->rd]; + TCGv Rr =3D cpu_r[a->rr]; + TCGv R =3D tcg_temp_new_i32(); + TCGv t0 =3D tcg_temp_new_i32(); + TCGv t1 =3D tcg_temp_new_i32(); + + tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */ + tcg_gen_ext8s_tl(t1, Rr); /* make Rr full 32 bit signed */ + tcg_gen_mul_tl(R, t0, t1); /* R =3D Rd *Rr */ + tcg_gen_shli_tl(R, R, 1); + + tcg_gen_andi_tl(R0, R, 0xff); + tcg_gen_shri_tl(R1, R, 8); + tcg_gen_andi_tl(R1, R1, 0xff); + + tcg_gen_shri_tl(cpu_Cf, R, 16); /* Cf =3D R(16) */ + tcg_gen_andi_tl(cpu_Zf, R, 0x0000ffff); + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(R); + + return true; +} + + +/* + * This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication + * and shifts the result one bit left. + */ +static bool trans_FMULSU(DisasContext *ctx, arg_FMULSU *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { + return true; + } + + TCGv R0 =3D cpu_r[0]; + TCGv R1 =3D cpu_r[1]; + TCGv Rd =3D cpu_r[a->rd]; + TCGv Rr =3D cpu_r[a->rr]; + TCGv R =3D tcg_temp_new_i32(); + TCGv t0 =3D tcg_temp_new_i32(); + + tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */ + tcg_gen_mul_tl(R, t0, Rr); /* R =3D Rd *Rr */ + tcg_gen_shli_tl(R, R, 1); + + tcg_gen_andi_tl(R0, R, 0xff); + tcg_gen_shri_tl(R1, R, 8); + tcg_gen_andi_tl(R1, R1, 0xff); + + tcg_gen_shri_tl(cpu_Cf, R, 16); /* Cf =3D R(16) */ + tcg_gen_andi_tl(cpu_Zf, R, 0x0000ffff); + + tcg_temp_free_i32(t0); + tcg_temp_free_i32(R); + + return true; +} + + +/* + * The module is an instruction set extension to the AVR CPU, performing + * DES iterations. The 64-bit data block (plaintext or ciphertext) is pla= ced in + * the CPU register file, registers R0-R7, where LSB of data is placed in= LSB + * of R0 and MSB of data is placed in MSB of R7. The full 64-bit key (inc= luding + * parity bits) is placed in registers R8- R15, organized in the register= file + * with LSB of key in LSB of R8 and MSB of key in MSB of R15. Executing o= ne DES + * instruction performs one round in the DES algorithm. Sixteen rounds mu= st be + * executed in increasing order to form the correct DES ciphertext or + * plaintext. Intermediate results are stored in the register file (R0-R1= 5) + * after each DES instruction. The instruction's operand (K) determines w= hich + * round is executed, and the half carry flag (H) determines whether encr= yption + * or decryption is performed. The DES algorithm is described in + * "Specifications for the Data Encryption Standard" (Federal Information + * Processing Standards Publication 46). Intermediate results in this + * implementation differ from the standard because the initial permutatio= n and + * the inverse initial permutation are performed each iteration. This doe= s not + * affect the result in the final ciphertext or plaintext, but reduces + * execution time. + */ +static bool trans_DES(DisasContext *ctx, arg_DES *a) +{ + /* TODO */ + if (!avr_have_feature(ctx, AVR_FEATURE_DES)) { + return true; + } + + return true; +} --=20 2.17.2 (Apple Git-113) From nobody Tue May 7 17:09:40 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1571073034; cv=none; d=zoho.com; s=zohoarc; b=BYHbcQm2LxN9A/jczWpZbBEdWBohjUehGZt6kcOUqMtup8c1+XrkQer0x0cUzfZmT061B6XQs7MVXOjasIoWdok120cW957AdQrfUHvxqrPk2GrHp8nB94MnpD/9clMvSey5vKLTZ2yNLB/IqWLFDwdv7ktQrKBJ4IX9z6Cftqs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1571073034; h=Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:Message-ID:References:Sender:Subject:To; bh=YKsFM0oxxSLBfiVZuIx8TDBtf3x+c2wKOGsJcqKU8dY=; b=TNr1lbbb6pz2Eb9FcLqvb8i61TLUqscq7e5hD/q/0lBVkjFgTGaS43UW9kumpgLuYrJymmiDjlCFAQUY24ZYCwmnki8k1YySD0EVr12ZrH0SJvDnxVXcanzUUAY5xIFUZo38/unPMtwV1actvFT/iSnEOm1ut/lXlSP1K0wPMOU= ARC-Authentication-Results: i=1; mx.zoho.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 157107303460644.63430521831663; Mon, 14 Oct 2019 10:10:34 -0700 (PDT) Received: from localhost ([::1]:54128 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iK3rd-0003mb-3F for importer@patchew.org; Mon, 14 Oct 2019 13:10:33 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:39821) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iK345-0006Dp-Q0 for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:23 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iK343-0007UY-L4 for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:21 -0400 Received: from mail-wr1-x441.google.com ([2a00:1450:4864:20::441]:37050) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1iK343-0007To-DO for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:19 -0400 Received: by mail-wr1-x441.google.com with SMTP id p14so20432832wro.4 for ; Mon, 14 Oct 2019 09:19:19 -0700 (PDT) Received: from 8c859074c0ff.ant.amazon.com.com (bzq-79-178-11-117.red.bezeqint.net. [79.178.11.117]) by smtp.gmail.com with ESMTPSA id c132sm28050861wme.27.2019.10.14.09.19.16 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 14 Oct 2019 09:19:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=YKsFM0oxxSLBfiVZuIx8TDBtf3x+c2wKOGsJcqKU8dY=; b=gP1sC98+12XWOpRNMpAofQxUpBA36H/WRGdFlGT92b5kTLOowqW0ggmuPbn3/IKdal aH2thRuTkQjx1IIQPQD8DTZ+A8FVhZPMO4QsOSH2h4Q/MLhLA9f2M1VpNUrF69GETHww w2MUaa7ciPWhATISbEtA2dFBNQNWHnfM/Eaqjhsa8mOjkSkWPBFdmNGLDlgYIZ6POGoe bgzmweVHGUUjkgF/BNI1cTprZGVMlyXezknfqSVvxrUdI5Csa6cecJuX9fqAT38Ld2og LCuaJ7mxMPufyjwKOc1WCXiGDvZvpU5VPBGYBBBS0te45WVWw9lOtFrQkc34fUEnI/qq eKnA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=YKsFM0oxxSLBfiVZuIx8TDBtf3x+c2wKOGsJcqKU8dY=; b=tFUW0HOT/oOiklqUy9470KI6HszNWHQ1AaCZkBKIU8CeyWW1FfScvxu4X4Qik8TreK sIeTCO2/kbfrI4kH5MEFj1Hp9O3DYYsB8sanqhcMR0yduzbEeQRqMWrB3QAa1n1TH87+ QDPibwBQSYOo8DbpQzvGl8rVDcqo4slPAG4Q6T5LcLcyLP2pWiqW8VjyczFQnh+eYNBJ g0wfeUxpg6UxhxIQG++DD3Zn+dfcOJObUdGckr5ktuyw1uat4HkbJNHoy8KkJ7Ro7UPE PLjTP/mk/kUlgNRlx6ZZH443yUP4r6sbF/ogZhY1mGuDr/+T2oE22jl3kJEzQ9gpeZCQ P2Pw== X-Gm-Message-State: APjAAAXCFAGiHIGZrGhOnB24DCCQTPlRipJOzQ8jsfSOGDCaSD8GD3Pd w1Hy9+T8hhDPwKcpAkGhOlcmYqq21Bo= X-Google-Smtp-Source: APXvYqy/F+sexNZM69Bpp4nw4cBc5v8TK9D4mW3hvDchT4JACdllo8Nm5FkDagjjl/WZHDWFpwi+Lw== X-Received: by 2002:a5d:4f8f:: with SMTP id d15mr11491686wru.126.1571069957846; Mon, 14 Oct 2019 09:19:17 -0700 (PDT) From: Michael Rolnik To: qemu-devel@nongnu.org Subject: [PATCH v32 06/13] target/avr: Add instruction translation - Branch Instructions Date: Mon, 14 Oct 2019 19:18:36 +0300 Message-Id: <20191014161843.84845-7-mrolnik@gmail.com> X-Mailer: git-send-email 2.17.2 (Apple Git-113) In-Reply-To: <20191014161843.84845-1-mrolnik@gmail.com> References: <20191014161843.84845-1-mrolnik@gmail.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::441 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: thuth@redhat.com, Michael Rolnik , richard.henderson@linaro.org, dovgaluk@ispras.ru, imammedo@redhat.com, philmd@redhat.com, aleksandar.m.mail@gmail.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This includes: - RJMP, IJMP, EIJMP, JMP - RCALL, ICALL, EICALL, CALL - RET, RETI - CPSE, CP, CPC, CPI - SBRC, SBRS, SBIC, SBIS - BRBC, BRBS Signed-off-by: Michael Rolnik --- target/avr/translate.c | 542 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 542 insertions(+) diff --git a/target/avr/translate.c b/target/avr/translate.c index 3eaa3e5099..3afd686ee8 100644 --- a/target/avr/translate.c +++ b/target/avr/translate.c @@ -224,6 +224,86 @@ static void gen_ZNSf(TCGv R) } =20 =20 +static void gen_push_ret(DisasContext *ctx, int ret) +{ + if (avr_feature(ctx->env, AVR_FEATURE_1_BYTE_PC)) { + + TCGv t0 =3D tcg_const_i32((ret & 0x0000ff)); + + tcg_gen_qemu_st_tl(t0, cpu_sp, MMU_DATA_IDX, MO_UB); + tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); + + tcg_temp_free_i32(t0); + } else if (avr_feature(ctx->env, AVR_FEATURE_2_BYTE_PC)) { + + TCGv t0 =3D tcg_const_i32((ret & 0x00ffff)); + + tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); + tcg_gen_qemu_st_tl(t0, cpu_sp, MMU_DATA_IDX, MO_BEUW); + tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); + + tcg_temp_free_i32(t0); + + } else if (avr_feature(ctx->env, AVR_FEATURE_3_BYTE_PC)) { + + TCGv lo =3D tcg_const_i32((ret & 0x0000ff)); + TCGv hi =3D tcg_const_i32((ret & 0xffff00) >> 8); + + tcg_gen_qemu_st_tl(lo, cpu_sp, MMU_DATA_IDX, MO_UB); + tcg_gen_subi_tl(cpu_sp, cpu_sp, 2); + tcg_gen_qemu_st_tl(hi, cpu_sp, MMU_DATA_IDX, MO_BEUW); + tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); + + tcg_temp_free_i32(lo); + tcg_temp_free_i32(hi); + } +} + + +static void gen_pop_ret(DisasContext *ctx, TCGv ret) +{ + if (avr_feature(ctx->env, AVR_FEATURE_1_BYTE_PC)) { + tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); + tcg_gen_qemu_ld_tl(ret, cpu_sp, MMU_DATA_IDX, MO_UB); + } else if (avr_feature(ctx->env, AVR_FEATURE_2_BYTE_PC)) { + tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); + tcg_gen_qemu_ld_tl(ret, cpu_sp, MMU_DATA_IDX, MO_BEUW); + tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); + } else if (avr_feature(ctx->env, AVR_FEATURE_3_BYTE_PC)) { + TCGv lo =3D tcg_temp_new_i32(); + TCGv hi =3D tcg_temp_new_i32(); + + tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); + tcg_gen_qemu_ld_tl(hi, cpu_sp, MMU_DATA_IDX, MO_BEUW); + + tcg_gen_addi_tl(cpu_sp, cpu_sp, 2); + tcg_gen_qemu_ld_tl(lo, cpu_sp, MMU_DATA_IDX, MO_UB); + + tcg_gen_deposit_tl(ret, lo, hi, 8, 16); + + tcg_temp_free_i32(lo); + tcg_temp_free_i32(hi); + } +} + + +static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) +{ + TranslationBlock *tb =3D ctx->tb; + + if (ctx->singlestep =3D=3D 0) { + tcg_gen_goto_tb(n); + tcg_gen_movi_i32(cpu_pc, dest); + tcg_gen_exit_tb(tb, n); + } else { + tcg_gen_movi_i32(cpu_pc, dest); + gen_helper_debug(cpu_env); + tcg_gen_exit_tb(NULL, 0); + } + ctx->bstate =3D DISAS_NORETURN; +} + + /* * Adds two registers without the C Flag and places the result in the * destination register Rd. @@ -941,3 +1021,465 @@ static bool trans_DES(DisasContext *ctx, arg_DES *a) =20 return true; } + + +/* + * Relative jump to an address within PC - 2K +1 and PC + 2K (words). For + * AVR microcontrollers with Program memory not exceeding 4K words (8KB) = this + * instruction can address the entire memory from every address location.= See + * also JMP. + */ +static bool trans_RJMP(DisasContext *ctx, arg_RJMP *a) +{ + int dst =3D ctx->npc + a->imm; + + gen_goto_tb(ctx, 0, dst); + + return true; +} + + +/* + * Indirect jump to the address pointed to by the Z (16 bits) Pointer + * Register in the Register File. The Z-pointer Register is 16 bits wide = and + * allows jump within the lowest 64K words (128KB) section of Program mem= ory. + * This instruction is not available in all devices. Refer to the device + * specific instruction set summary. + */ +static bool trans_IJMP(DisasContext *ctx, arg_IJMP *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_IJMP_ICALL)) { + return true; + } + + gen_jmp_z(ctx); + + return true; +} + + +/* + * Indirect jump to the address pointed to by the Z (16 bits) Pointer + * Register in the Register File and the EIND Register in the I/O space. = This + * instruction allows for indirect jumps to the entire 4M (words) Program + * memory space. See also IJMP. This instruction is not available in all + * devices. Refer to the device specific instruction set summary. + */ +static bool trans_EIJMP(DisasContext *ctx, arg_EIJMP *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_EIJMP_EICALL)) { + return true; + } + + gen_jmp_ez(ctx); + return true; +} + + +/* + * Jump to an address within the entire 4M (words) Program memory. See al= so + * RJMP. This instruction is not available in all devices. Refer to the = device + * specific instruction set summary.0 + */ +static bool trans_JMP(DisasContext *ctx, arg_JMP *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_JMP_CALL)) { + return true; + } + + gen_goto_tb(ctx, 0, a->imm); + + return true; +} + + +/* + * Relative call to an address within PC - 2K + 1 and PC + 2K (words). The + * return address (the instruction after the RCALL) is stored onto the St= ack. + * See also CALL. For AVR microcontrollers with Program memory not exceed= ing 4K + * words (8KB) this instruction can address the entire memory from every + * address location. The Stack Pointer uses a post-decrement scheme during + * RCALL. + */ +static bool trans_RCALL(DisasContext *ctx, arg_RCALL *a) +{ + int ret =3D ctx->npc; + int dst =3D ctx->npc + a->imm; + + gen_push_ret(ctx, ret); + gen_goto_tb(ctx, 0, dst); + + return true; +} + + +/* + * Calls to a subroutine within the entire 4M (words) Program memory. The + * return address (to the instruction after the CALL) will be stored onto= the + * Stack. See also RCALL. The Stack Pointer uses a post-decrement scheme = during + * CALL. This instruction is not available in all devices. Refer to the = device + * specific instruction set summary. + */ +static bool trans_ICALL(DisasContext *ctx, arg_ICALL *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_IJMP_ICALL)) { + return true; + } + + int ret =3D ctx->npc; + + gen_push_ret(ctx, ret); + gen_jmp_z(ctx); + + return true; +} + + +/* + * Indirect call of a subroutine pointed to by the Z (16 bits) Pointer + * Register in the Register File and the EIND Register in the I/O space. = This + * instruction allows for indirect calls to the entire 4M (words) Program + * memory space. See also ICALL. The Stack Pointer uses a post-decrement = scheme + * during EICALL. This instruction is not available in all devices. Refe= r to + * the device specific instruction set summary. + */ +static bool trans_EICALL(DisasContext *ctx, arg_EICALL *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_EIJMP_EICALL)) { + return true; + } + + int ret =3D ctx->npc; + + gen_push_ret(ctx, ret); + gen_jmp_ez(ctx); + return true; +} + + +/* + * Calls to a subroutine within the entire Program memory. The return + * address (to the instruction after the CALL) will be stored onto the St= ack. + * (See also RCALL). The Stack Pointer uses a post-decrement scheme during + * CALL. This instruction is not available in all devices. Refer to the = device + * specific instruction set summary. + */ +static bool trans_CALL(DisasContext *ctx, arg_CALL *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_JMP_CALL)) { + return true; + } + + int Imm =3D a->imm; + int ret =3D ctx->npc; + + gen_push_ret(ctx, ret); + gen_goto_tb(ctx, 0, Imm); + + return true; +} + + +/* + * Returns from subroutine. The return address is loaded from the STACK. + * The Stack Pointer uses a preincrement scheme during RET. + */ +static bool trans_RET(DisasContext *ctx, arg_RET *a) +{ + gen_pop_ret(ctx, cpu_pc); + + ctx->bstate =3D DISAS_LOOKUP; + return true; +} + + +/* + * Returns from interrupt. The return address is loaded from the STACK and + * the Global Interrupt Flag is set. Note that the Status Register is not + * automatically stored when entering an interrupt routine, and it is not + * restored when returning from an interrupt routine. This must be handle= d by + * the application program. The Stack Pointer uses a pre-increment scheme + * during RETI. + */ +static bool trans_RETI(DisasContext *ctx, arg_RETI *a) +{ + gen_pop_ret(ctx, cpu_pc); + tcg_gen_movi_tl(cpu_If, 1); + + /* Need to return to main loop to re-evaluate interrupts. */ + ctx->bstate =3D DISAS_EXIT; + return true; +} + + +/* + * This instruction performs a compare between two registers Rd and Rr, a= nd + * skips the next instruction if Rd =3D Rr. + */ +static bool trans_CPSE(DisasContext *ctx, arg_CPSE *a) +{ + ctx->skip_cond =3D TCG_COND_EQ; + ctx->skip_var0 =3D cpu_r[a->rd]; + ctx->skip_var1 =3D cpu_r[a->rr]; + return true; +} + + +/* + * This instruction performs a compare between two registers Rd and Rr. + * None of the registers are changed. All conditional branches can be used + * after this instruction. + */ +static bool trans_CP(DisasContext *ctx, arg_CP *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv Rr =3D cpu_r[a->rr]; + TCGv R =3D tcg_temp_new_i32(); + + /* op */ + tcg_gen_sub_tl(R, Rd, Rr); /* R =3D Rd - Rr */ + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + gen_sub_CHf(R, Rd, Rr); + gen_sub_Vf(R, Rd, Rr); + gen_ZNSf(R); + + tcg_temp_free_i32(R); + + return true; +} + + +/* + * This instruction performs a compare between two registers Rd and Rr and + * also takes into account the previous carry. None of the registers are + * changed. All conditional branches can be used after this instruction. + */ +static bool trans_CPC(DisasContext *ctx, arg_CPC *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv Rr =3D cpu_r[a->rr]; + TCGv R =3D tcg_temp_new_i32(); + + /* op */ + tcg_gen_sub_tl(R, Rd, Rr); /* R =3D Rd - Rr - Cf */ + tcg_gen_sub_tl(R, R, cpu_Cf); + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + gen_sub_CHf(R, Rd, Rr); + gen_sub_Vf(R, Rd, Rr); + gen_NSf(R); + + /* + * Previous value remains unchanged when the result is zero; + * cleared otherwise. + */ + tcg_gen_or_tl(cpu_Zf, cpu_Zf, R); + + tcg_temp_free_i32(R); + + return true; +} + + +/* + * This instruction performs a compare between register Rd and a constant. + * The register is not changed. All conditional branches can be used afte= r this + * instruction. + */ +static bool trans_CPI(DisasContext *ctx, arg_CPI *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + int Imm =3D a->imm; + TCGv Rr =3D tcg_const_i32(Imm); + TCGv R =3D tcg_temp_new_i32(); + + /* op */ + tcg_gen_sub_tl(R, Rd, Rr); /* R =3D Rd - Rr */ + tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ + + gen_sub_CHf(R, Rd, Rr); + gen_sub_Vf(R, Rd, Rr); + gen_ZNSf(R); + + tcg_temp_free_i32(R); + tcg_temp_free_i32(Rr); + + return true; +} + + +/* + * This instruction tests a single bit in a register and skips the next + * instruction if the bit is cleared. + */ +static bool trans_SBRC(DisasContext *ctx, arg_SBRC *a) +{ + TCGv Rr =3D cpu_r[a->rr]; + + ctx->skip_cond =3D TCG_COND_EQ; + ctx->skip_var0 =3D tcg_temp_new(); + ctx->free_skip_var0 =3D true; + + tcg_gen_andi_tl(ctx->skip_var0, Rr, 1 << a->bit); + return true; +} + + +/* + * This instruction tests a single bit in a register and skips the next + * instruction if the bit is set. + */ +static bool trans_SBRS(DisasContext *ctx, arg_SBRS *a) +{ + TCGv Rr =3D cpu_r[a->rr]; + + ctx->skip_cond =3D TCG_COND_NE; + ctx->skip_var0 =3D tcg_temp_new(); + ctx->free_skip_var0 =3D true; + + tcg_gen_andi_tl(ctx->skip_var0, Rr, 1 << a->bit); + return true; +} + + +/* + * This instruction tests a single bit in an I/O Register and skips the + * next instruction if the bit is cleared. This instruction operates on t= he + * lower 32 I/O Registers -- addresses 0-31. + */ +static bool trans_SBIC(DisasContext *ctx, arg_SBIC *a) +{ + TCGv temp =3D tcg_const_i32(a->reg); + + gen_helper_inb(temp, cpu_env, temp); + tcg_gen_andi_tl(temp, temp, 1 << a->bit); + ctx->skip_cond =3D TCG_COND_EQ; + ctx->skip_var0 =3D temp; + ctx->free_skip_var0 =3D true; + + return true; +} + + +/* + * This instruction tests a single bit in an I/O Register and skips the + * next instruction if the bit is set. This instruction operates on the l= ower + * 32 I/O Registers -- addresses 0-31. + */ +static bool trans_SBIS(DisasContext *ctx, arg_SBIS *a) +{ + TCGv temp =3D tcg_const_i32(a->reg); + + gen_helper_inb(temp, cpu_env, temp); + tcg_gen_andi_tl(temp, temp, 1 << a->bit); + ctx->skip_cond =3D TCG_COND_NE; + ctx->skip_var0 =3D temp; + ctx->free_skip_var0 =3D true; + + return true; +} + + +/* + * Conditional relative branch. Tests a single bit in SREG and branches + * relatively to PC if the bit is cleared. This instruction branches rela= tively + * to PC in either direction (PC - 63 < =3D destination <=3D PC + 64). The + * parameter k is the offset from PC and is represented in two's compleme= nt + * form. + */ +static bool trans_BRBC(DisasContext *ctx, arg_BRBC *a) +{ + TCGLabel *not_taken =3D gen_new_label(); + TCGCond cond =3D TCG_COND_EQ; + TCGv var; + + switch (a->bit) { + case 0x00: + var =3D cpu_Cf; + break; + case 0x01: + cond =3D TCG_COND_NE; + var =3D cpu_Zf; + break; + case 0x02: + var =3D cpu_Nf; + break; + case 0x03: + var =3D cpu_Vf; + break; + case 0x04: + var =3D cpu_Sf; + break; + case 0x05: + var =3D cpu_Hf; + break; + case 0x06: + var =3D cpu_Tf; + break; + case 0x07: + var =3D cpu_If; + break; + default: + g_assert_not_reached(); + } + + tcg_gen_brcondi_i32(tcg_invert_cond(cond), var, 0, not_taken); + gen_goto_tb(ctx, 0, ctx->npc + a->imm); + gen_set_label(not_taken); + + ctx->bstate =3D DISAS_CHAIN; + return true; +} + + +/* + * Conditional relative branch. Tests a single bit in SREG and branches + * relatively to PC if the bit is set. This instruction branches relative= ly to + * PC in either direction (PC - 63 < =3D destination <=3D PC + 64). The p= arameter k + * is the offset from PC and is represented in two's complement form. + */ +static bool trans_BRBS(DisasContext *ctx, arg_BRBS *a) +{ + TCGLabel *not_taken =3D gen_new_label(); + TCGCond cond =3D TCG_COND_NE; + TCGv var; + + switch (a->bit) { + case 0x00: + var =3D cpu_Cf; + break; + case 0x01: + cond =3D TCG_COND_EQ; + var =3D cpu_Zf; + break; + case 0x02: + var =3D cpu_Nf; + break; + case 0x03: + var =3D cpu_Vf; + break; + case 0x04: + var =3D cpu_Sf; + break; + case 0x05: + var =3D cpu_Hf; + break; + case 0x06: + var =3D cpu_Tf; + break; + case 0x07: + var =3D cpu_If; + break; + default: + g_assert_not_reached(); + } + + tcg_gen_brcondi_i32(tcg_invert_cond(cond), var, 0, not_taken); + gen_goto_tb(ctx, 0, ctx->npc + a->imm); + gen_set_label(not_taken); + + ctx->bstate =3D DISAS_CHAIN; + return true; +} + --=20 2.17.2 (Apple Git-113) From nobody Tue May 7 17:09:40 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1571074299; cv=none; d=zoho.com; s=zohoarc; b=QWeWolhb2fdBeECEnD+U1cht36ceUbFsSE/U5U+5+QKJxqPU3ZKcEjyXyJ6Fvi4vBMx8zkf5XmbPPGbmMzC3FYXve+4cKLm7zcLu1SjYPATOQr+okYZMZEtvcaCdeZ7TvdQ7LJBLQmOASsPcW8laogrKAyI2lBmCWxVhQY3rBgk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1571074299; h=Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:Message-ID:References:Sender:Subject:To; bh=aawyhmteAoA4eTVwBLshfPsFb23WLn2wHQ8KTF2itNw=; b=N+iw3FgKZ7pC/uSdQnvu1MXdM37FYyJwzo4VWoT9O8DwXCuql7W7Bu9XYw67Xy1Oofv0INsLvb4E+SLmFijjVBMVghF8ceUmY6bVRGiBv0uKBANxZQAAsdSbX2ZArDjffoS0Yxrz/Q8xbaOOurvLrupKIe+sPpkxyuJUsjC1sXI= ARC-Authentication-Results: i=1; mx.zoho.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1571074299045355.3718117699044; Mon, 14 Oct 2019 10:31:39 -0700 (PDT) Received: from localhost ([::1]:54584 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iK4By-0005jw-BD for importer@patchew.org; Mon, 14 Oct 2019 13:31:34 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:39848) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iK34A-0006Jo-1n for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:29 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iK345-0007V6-Vg for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:25 -0400 Received: from mail-wm1-x342.google.com ([2a00:1450:4864:20::342]:51781) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1iK345-0007Ut-Lb for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:21 -0400 Received: by mail-wm1-x342.google.com with SMTP id 7so17925997wme.1 for ; Mon, 14 Oct 2019 09:19:21 -0700 (PDT) Received: from 8c859074c0ff.ant.amazon.com.com (bzq-79-178-11-117.red.bezeqint.net. [79.178.11.117]) by smtp.gmail.com with ESMTPSA id c132sm28050861wme.27.2019.10.14.09.19.17 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 14 Oct 2019 09:19:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=aawyhmteAoA4eTVwBLshfPsFb23WLn2wHQ8KTF2itNw=; b=U7iyeyL0dLiZVxZt5+wkBnfKddJbUJ0C7nTMyrGAy1TgWgBuTbgqYk0X17BbGClcKU 0lzc+YLchW2rhXIA3gN6qT2VqHWjTZmU6I9msq542dnPNyKMCrJ9LEPZHznQG5ENTmgE oXd5ionaelpPc9Ea9BDpWQeFnfABRLn8h5lEkgh+Tvn1nse1TPWleL0d6aeNNyIv2NCB gIwfN9XsfqV/uOO0IrQI8Sj2cnbPEHDg8f16IQvqAyoW5vO0yTZDYICTqflTPhmOb2DA m/fOWbXOoWo1mYWRpv02Y3Zpg2g6nfBo40Ue726OCLm2/+Nu86kwJmSkFGTntHYlvA6G xvSg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=aawyhmteAoA4eTVwBLshfPsFb23WLn2wHQ8KTF2itNw=; b=s7iwsOh9EmWipHe7bxCKfxUzxuf7lEatlU87eOJTgnQ4ZDHrAZDjGAiG+ooHPRuXeJ erws576FRvKv9ak/mjFwPzV1HBeZYikJQOtQmwCyeDnNG5oUytO9Qe5ae5KNcvSgpY/l KoRf6e7nkdWMF7Tj+KWNMgwh8HcI5VdOiUEYjSYPwq57UOybi52VAtb7rCL4B2lQC+g6 JNvz+439uoEPDMgCIqhEBYKfkRXtghkC+vd4NG/QCGG0hrUHlfGe8qd7sKABPDdk9umX /MYSz2gzoCKEo431hPW60HU9+vxMrt1cCdQLJSVj5xoMERLc/c2ntN+xn0HuTrkcklJN 14Hg== X-Gm-Message-State: APjAAAXc5dAwbmJijbWjpNObyWR5r9nbIxt9o9MssT9TC2l1ex28BgRv lH02FAVbWVrIrfw1Ws0+mOY7pq69410= X-Google-Smtp-Source: APXvYqzKj+0ooRO0bJ79FayWSGgBctFP9XWNxVc++5Ade09qV8WdtG2Kh/tBm+oCRpY/4U7IWfw5VQ== X-Received: by 2002:a1c:8148:: with SMTP id c69mr16408945wmd.41.1571069959670; Mon, 14 Oct 2019 09:19:19 -0700 (PDT) From: Michael Rolnik To: qemu-devel@nongnu.org Subject: [PATCH v32 07/13] target/avr: Add instruction translation - Bit and Bit-test Instructions Date: Mon, 14 Oct 2019 19:18:37 +0300 Message-Id: <20191014161843.84845-8-mrolnik@gmail.com> X-Mailer: git-send-email 2.17.2 (Apple Git-113) In-Reply-To: <20191014161843.84845-1-mrolnik@gmail.com> References: <20191014161843.84845-1-mrolnik@gmail.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::342 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: thuth@redhat.com, Michael Rolnik , richard.henderson@linaro.org, dovgaluk@ispras.ru, imammedo@redhat.com, philmd@redhat.com, aleksandar.m.mail@gmail.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This includes: - LSR, ROR - ASR - SWAP - SBI, CBI - BST, BLD - BSET, BCLR Signed-off-by: Michael Rolnik --- target/avr/translate.c | 1123 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1123 insertions(+) diff --git a/target/avr/translate.c b/target/avr/translate.c index 3afd686ee8..19540634df 100644 --- a/target/avr/translate.c +++ b/target/avr/translate.c @@ -304,6 +304,15 @@ static void gen_goto_tb(DisasContext *ctx, int n, targ= et_ulong dest) } =20 =20 +static void gen_rshift_ZNVSf(TCGv R) +{ + tcg_gen_mov_tl(cpu_Zf, R); /* Zf =3D R */ + tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf =3D R(7) */ + tcg_gen_xor_tl(cpu_Vf, cpu_Nf, cpu_Cf); + tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf =3D Nf ^ Vf */ +} + + /* * Adds two registers without the C Flag and places the result in the * destination register Rd. @@ -1483,3 +1492,1117 @@ static bool trans_BRBS(DisasContext *ctx, arg_BRBS= *a) return true; } =20 + +/* + * This instruction makes a copy of one register into another. The source + * register Rr is left unchanged, while the destination register Rd is lo= aded + * with a copy of Rr. + */ +static bool trans_MOV(DisasContext *ctx, arg_MOV *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv Rr =3D cpu_r[a->rr]; + + tcg_gen_mov_tl(Rd, Rr); + + return true; +} + + +/* + * This instruction makes a copy of one register pair into another regist= er + * pair. The source register pair Rr+1:Rr is left unchanged, while the + * destination register pair Rd+1:Rd is loaded with a copy of Rr + 1:Rr. = This + * instruction is not available in all devices. Refer to the device speci= fic + * instruction set summary. + */ +static bool trans_MOVW(DisasContext *ctx, arg_MOVW *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_MOVW)) { + return true; + } + + TCGv RdL =3D cpu_r[a->rd]; + TCGv RdH =3D cpu_r[a->rd + 1]; + TCGv RrL =3D cpu_r[a->rr]; + TCGv RrH =3D cpu_r[a->rr + 1]; + + tcg_gen_mov_tl(RdH, RrH); + tcg_gen_mov_tl(RdL, RrL); + + return true; +} + + +/* + * Loads an 8 bit constant directly to register 16 to 31. + */ +static bool trans_LDI(DisasContext *ctx, arg_LDI *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + int imm =3D a->imm; + + tcg_gen_movi_tl(Rd, imm); + + return true; +} + + +/* + * Loads one byte from the data space to a register. For parts with SRAM, + * the data space consists of the Register File, I/O memory and internal = SRAM + * (and external SRAM if applicable). For parts without SRAM, the data sp= ace + * consists of the register file only. The EEPROM has a separate address = space. + * A 16-bit address must be supplied. Memory access is limited to the cur= rent + * data segment of 64KB. The LDS instruction uses the RAMPD Register to a= ccess + * memory above 64KB. To access another data segment in devices with more= than + * 64KB data space, the RAMPD in register in the I/O area has to be chang= ed. + * This instruction is not available in all devices. Refer to the device + * specific instruction set summary. + */ +static bool trans_LDS(DisasContext *ctx, arg_LDS *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv addr =3D tcg_temp_new_i32(); + TCGv H =3D cpu_rampD; + a->imm =3D next_word(ctx); + + tcg_gen_mov_tl(addr, H); /* addr =3D H:M:L */ + tcg_gen_shli_tl(addr, addr, 16); + tcg_gen_ori_tl(addr, addr, a->imm); + + gen_data_load(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + + +/* + * Loads one byte indirect from the data space to a register. For parts + * with SRAM, the data space consists of the Register File, I/O memory and + * internal SRAM (and external SRAM if applicable). For parts without SRA= M, the + * data space consists of the Register File only. In some parts the Flash + * Memory has been mapped to the data space and can be read using this co= mmand. + * The EEPROM has a separate address space. The data location is pointed= to by + * the X (16 bits) Pointer Register in the Register File. Memory access is + * limited to the current data segment of 64KB. To access another data se= gment + * in devices with more than 64KB data space, the RAMPX in register in th= e I/O + * area has to be changed. The X-pointer Register can either be left unc= hanged + * by the operation, or it can be post-incremented or predecremented. Th= ese + * features are especially suited for accessing arrays, tables, and Stack + * Pointer usage of the X-pointer Register. Note that only the low byte o= f the + * X-pointer is updated in devices with no more than 256 bytes data space= . For + * such devices, the high byte of the pointer is not used by this instruc= tion + * and can be used for other purposes. The RAMPX Register in the I/O area= is + * updated in parts with more than 64KB data space or more than 64KB Prog= ram + * memory, and the increment/decrement is added to the entire 24-bit addr= ess on + * such devices. Not all variants of this instruction is available in all + * devices. Refer to the device specific instruction set summary. In the + * Reduced Core tinyAVR the LD instruction can be used to achieve the same + * operation as LPM since the program memory is mapped to the data memory + * space. + */ +static bool trans_LDX1(DisasContext *ctx, arg_LDX1 *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv addr =3D gen_get_xaddr(); + + gen_data_load(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + + +static bool trans_LDX2(DisasContext *ctx, arg_LDX2 *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv addr =3D gen_get_xaddr(); + + gen_data_load(ctx, Rd, addr); + tcg_gen_addi_tl(addr, addr, 1); /* addr =3D addr + 1 */ + + gen_set_xaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + + +static bool trans_LDX3(DisasContext *ctx, arg_LDX3 *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv addr =3D gen_get_xaddr(); + + tcg_gen_subi_tl(addr, addr, 1); /* addr =3D addr - 1 */ + gen_data_load(ctx, Rd, addr); + gen_set_xaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + + +static bool trans_STX1(DisasContext *ctx, arg_STX1 *a) +{ + TCGv Rd =3D cpu_r[a->rr]; + TCGv addr =3D gen_get_xaddr(); + + gen_data_store(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_STX2(DisasContext *ctx, arg_STX2 *a) +{ + TCGv Rd =3D cpu_r[a->rr]; + TCGv addr =3D gen_get_xaddr(); + + gen_data_store(ctx, Rd, addr); + tcg_gen_addi_tl(addr, addr, 1); /* addr =3D addr + 1 */ + gen_set_xaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + +static bool trans_STX3(DisasContext *ctx, arg_STX3 *a) +{ + TCGv Rd =3D cpu_r[a->rr]; + TCGv addr =3D gen_get_xaddr(); + + tcg_gen_subi_tl(addr, addr, 1); /* addr =3D addr - 1 */ + gen_data_store(ctx, Rd, addr); + gen_set_xaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + + +/* + * Loads one byte indirect with or without displacement from the data spa= ce + * to a register. For parts with SRAM, the data space consists of the Reg= ister + * File, I/O memory and internal SRAM (and external SRAM if applicable). = For + * parts without SRAM, the data space consists of the Register File only.= In + * some parts the Flash Memory has been mapped to the data space and can = be + * read using this command. The EEPROM has a separate address space. The= data + * location is pointed to by the Y (16 bits) Pointer Register in the Regi= ster + * File. Memory access is limited to the current data segment of 64KB. To + * access another data segment in devices with more than 64KB data space,= the + * RAMPY in register in the I/O area has to be changed. The Y-pointer Re= gister + * can either be left unchanged by the operation, or it can be post-incre= mented + * or predecremented. These features are especially suited for accessing + * arrays, tables, and Stack Pointer usage of the Y-pointer Register. Not= e that + * only the low byte of the Y-pointer is updated in devices with no more = than + * 256 bytes data space. For such devices, the high byte of the pointer i= s not + * used by this instruction and can be used for other purposes. The RAMPY + * Register in the I/O area is updated in parts with more than 64KB data = space + * or more than 64KB Program memory, and the increment/decrement/displace= ment + * is added to the entire 24-bit address on such devices. Not all varian= ts of + * this instruction is available in all devices. Refer to the device spec= ific + * instruction set summary. In the Reduced Core tinyAVR the LD instructi= on can + * be used to achieve the same operation as LPM since the program memory = is + * mapped to the data memory space. + */ +static bool trans_LDY2(DisasContext *ctx, arg_LDY2 *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv addr =3D gen_get_yaddr(); + + gen_data_load(ctx, Rd, addr); + tcg_gen_addi_tl(addr, addr, 1); /* addr =3D addr + 1 */ + + gen_set_yaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + + +static bool trans_LDY3(DisasContext *ctx, arg_LDY3 *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv addr =3D gen_get_yaddr(); + + tcg_gen_subi_tl(addr, addr, 1); /* addr =3D addr - 1 */ + gen_data_load(ctx, Rd, addr); + gen_set_yaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + + +static bool trans_LDDY(DisasContext *ctx, arg_LDDY *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv addr =3D gen_get_yaddr(); + + tcg_gen_addi_tl(addr, addr, a->imm); /* addr =3D addr + q */ + gen_data_load(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + + +static bool trans_STY2(DisasContext *ctx, arg_STY2 *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv addr =3D gen_get_yaddr(); + + gen_data_store(ctx, Rd, addr); + tcg_gen_addi_tl(addr, addr, 1); /* addr =3D addr + 1 */ + gen_set_yaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + + +static bool trans_STY3(DisasContext *ctx, arg_STY3 *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv addr =3D gen_get_yaddr(); + + tcg_gen_subi_tl(addr, addr, 1); /* addr =3D addr - 1 */ + gen_data_store(ctx, Rd, addr); + gen_set_yaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + + +static bool trans_STDY(DisasContext *ctx, arg_STDY *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv addr =3D gen_get_yaddr(); + + tcg_gen_addi_tl(addr, addr, a->imm); /* addr =3D addr + q */ + gen_data_store(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + + +/* + * Loads one byte indirect with or without displacement from the data spa= ce + * to a register. For parts with SRAM, the data space consists of the Reg= ister + * File, I/O memory and internal SRAM (and external SRAM if applicable). = For + * parts without SRAM, the data space consists of the Register File only.= In + * some parts the Flash Memory has been mapped to the data space and can = be + * read using this command. The EEPROM has a separate address space. The= data + * location is pointed to by the Z (16 bits) Pointer Register in the Regi= ster + * File. Memory access is limited to the current data segment of 64KB. To + * access another data segment in devices with more than 64KB data space,= the + * RAMPZ in register in the I/O area has to be changed. The Z-pointer Re= gister + * can either be left unchanged by the operation, or it can be post-incre= mented + * or predecremented. These features are especially suited for Stack Poi= nter + * usage of the Z-pointer Register, however because the Z-pointer Registe= r can + * be used for indirect subroutine calls, indirect jumps and table lookup= , it + * is often more convenient to use the X or Y-pointer as a dedicated Stack + * Pointer. Note that only the low byte of the Z-pointer is updated in de= vices + * with no more than 256 bytes data space. For such devices, the high byt= e of + * the pointer is not used by this instruction and can be used for other + * purposes. The RAMPZ Register in the I/O area is updated in parts with = more + * than 64KB data space or more than 64KB Program memory, and the + * increment/decrement/displacement is added to the entire 24-bit address= on + * such devices. Not all variants of this instruction is available in all + * devices. Refer to the device specific instruction set summary. In the + * Reduced Core tinyAVR the LD instruction can be used to achieve the same + * operation as LPM since the program memory is mapped to the data memory + * space. For using the Z-pointer for table lookup in Program memory see= the + * LPM and ELPM instructions. + */ +static bool trans_LDZ2(DisasContext *ctx, arg_LDZ2 *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv addr =3D gen_get_zaddr(); + + gen_data_load(ctx, Rd, addr); + tcg_gen_addi_tl(addr, addr, 1); /* addr =3D addr + 1 */ + + gen_set_zaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + + +static bool trans_LDZ3(DisasContext *ctx, arg_LDZ3 *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv addr =3D gen_get_zaddr(); + + tcg_gen_subi_tl(addr, addr, 1); /* addr =3D addr - 1 */ + gen_data_load(ctx, Rd, addr); + + gen_set_zaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + + +static bool trans_LDDZ(DisasContext *ctx, arg_LDDZ *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv addr =3D gen_get_zaddr(); + + tcg_gen_addi_tl(addr, addr, a->imm); /* addr =3D addr + q */ + gen_data_load(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + + +static bool trans_STZ2(DisasContext *ctx, arg_STZ2 *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv addr =3D gen_get_zaddr(); + + gen_data_store(ctx, Rd, addr); + tcg_gen_addi_tl(addr, addr, 1); /* addr =3D addr + 1 */ + + gen_set_zaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + + +static bool trans_STZ3(DisasContext *ctx, arg_STZ3 *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv addr =3D gen_get_zaddr(); + + tcg_gen_subi_tl(addr, addr, 1); /* addr =3D addr - 1 */ + gen_data_store(ctx, Rd, addr); + + gen_set_zaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + + +static bool trans_STDZ(DisasContext *ctx, arg_STDZ *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv addr =3D gen_get_zaddr(); + + tcg_gen_addi_tl(addr, addr, a->imm); /* addr =3D addr + q */ + gen_data_store(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + + + +/* + * Stores one byte from a Register to the data space. For parts with SRAM, + * the data space consists of the Register File, I/O memory and internal = SRAM + * (and external SRAM if applicable). For parts without SRAM, the data sp= ace + * consists of the Register File only. The EEPROM has a separate address = space. + * A 16-bit address must be supplied. Memory access is limited to the cur= rent + * data segment of 64KB. The STS instruction uses the RAMPD Register to a= ccess + * memory above 64KB. To access another data segment in devices with more= than + * 64KB data space, the RAMPD in register in the I/O area has to be chang= ed. + * This instruction is not available in all devices. Refer to the device + * specific instruction set summary. + */ +static bool trans_STS(DisasContext *ctx, arg_STS *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv addr =3D tcg_temp_new_i32(); + TCGv H =3D cpu_rampD; + a->imm =3D next_word(ctx); + + tcg_gen_mov_tl(addr, H); /* addr =3D H:M:L */ + tcg_gen_shli_tl(addr, addr, 16); + tcg_gen_ori_tl(addr, addr, a->imm); + + gen_data_store(ctx, Rd, addr); + + tcg_temp_free_i32(addr); + + return true; +} + + +/* + * Loads one byte pointed to by the Z-register into the destination + * register Rd. This instruction features a 100% space effective constant + * initialization or constant data fetch. The Program memory is organized= in + * 16-bit words while the Z-pointer is a byte address. Thus, the least + * significant bit of the Z-pointer selects either low byte (ZLSB =3D 0) = or high + * byte (ZLSB =3D 1). This instruction can address the first 64KB (32K wo= rds) of + * Program memory. The Zpointer Register can either be left unchanged by = the + * operation, or it can be incremented. The incrementation does not apply= to + * the RAMPZ Register. Devices with Self-Programming capability can use = the + * LPM instruction to read the Fuse and Lock bit values. Refer to the de= vice + * documentation for a detailed description. The LPM instruction is not + * available in all devices. Refer to the device specific instruction set + * summary + */ +static bool trans_LPM1(DisasContext *ctx, arg_LPM1 *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_LPM)) { + return true; + } + + TCGv Rd =3D cpu_r[0]; + TCGv addr =3D tcg_temp_new_i32(); + TCGv H =3D cpu_r[31]; + TCGv L =3D cpu_r[30]; + + tcg_gen_shli_tl(addr, H, 8); /* addr =3D H:L */ + tcg_gen_or_tl(addr, addr, L); + + tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd =3D mem[addr] */ + + tcg_temp_free_i32(addr); + + return true; +} + + +static bool trans_LPM2(DisasContext *ctx, arg_LPM2 *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_LPM)) { + return true; + } + + TCGv Rd =3D cpu_r[a->rd]; + TCGv addr =3D tcg_temp_new_i32(); + TCGv H =3D cpu_r[31]; + TCGv L =3D cpu_r[30]; + + tcg_gen_shli_tl(addr, H, 8); /* addr =3D H:L */ + tcg_gen_or_tl(addr, addr, L); + + tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd =3D mem[addr] */ + + tcg_temp_free_i32(addr); + + return true; +} + + +static bool trans_LPMX(DisasContext *ctx, arg_LPMX *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_LPMX)) { + return true; + } + + TCGv Rd =3D cpu_r[a->rd]; + TCGv addr =3D tcg_temp_new_i32(); + TCGv H =3D cpu_r[31]; + TCGv L =3D cpu_r[30]; + + tcg_gen_shli_tl(addr, H, 8); /* addr =3D H:L */ + tcg_gen_or_tl(addr, addr, L); + + tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd =3D mem[addr] */ + + tcg_gen_addi_tl(addr, addr, 1); /* addr =3D addr + 1 */ + + tcg_gen_andi_tl(L, addr, 0xff); + + tcg_gen_shri_tl(addr, addr, 8); + tcg_gen_andi_tl(H, addr, 0xff); + + tcg_temp_free_i32(addr); + + return true; +} + + +/* + * Loads one byte pointed to by the Z-register and the RAMPZ Register in + * the I/O space, and places this byte in the destination register Rd. Th= is + * instruction features a 100% space effective constant initialization or + * constant data fetch. The Program memory is organized in 16-bit words w= hile + * the Z-pointer is a byte address. Thus, the least significant bit of the + * Z-pointer selects either low byte (ZLSB =3D 0) or high byte (ZLSB =3D = 1). This + * instruction can address the entire Program memory space. The Z-pointer + * Register can either be left unchanged by the operation, or it can be + * incremented. The incrementation applies to the entire 24-bit concatena= tion + * of the RAMPZ and Z-pointer Registers. Devices with Self-Programming + * capability can use the ELPM instruction to read the Fuse and Lock bit = value. + * Refer to the device documentation for a detailed description. This + * instruction is not available in all devices. Refer to the device speci= fic + * instruction set summary. + */ +static bool trans_ELPM1(DisasContext *ctx, arg_ELPM1 *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_ELPM)) { + return true; + } + + TCGv Rd =3D cpu_r[0]; + TCGv addr =3D gen_get_zaddr(); + + tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd =3D mem[addr] */ + + tcg_temp_free_i32(addr); + + return true; +} + + +static bool trans_ELPM2(DisasContext *ctx, arg_ELPM2 *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_ELPM)) { + return true; + } + + TCGv Rd =3D cpu_r[a->rd]; + TCGv addr =3D gen_get_zaddr(); + + tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd =3D mem[addr] */ + + tcg_temp_free_i32(addr); + + return true; +} + + +static bool trans_ELPMX(DisasContext *ctx, arg_ELPMX *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_ELPMX)) { + return true; + } + + TCGv Rd =3D cpu_r[a->rd]; + TCGv addr =3D gen_get_zaddr(); + + tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd =3D mem[addr] */ + + tcg_gen_addi_tl(addr, addr, 1); /* addr =3D addr + 1 */ + + gen_set_zaddr(addr); + + tcg_temp_free_i32(addr); + + return true; +} + + +/* + * SPM can be used to erase a page in the Program memory, to write a page + * in the Program memory (that is already erased), and to set Boot Loader= Lock + * bits. In some devices, the Program memory can be written one word at a= time, + * in other devices an entire page can be programmed simultaneously after= first + * filling a temporary page buffer. In all cases, the Program memory must= be + * erased one page at a time. When erasing the Program memory, the RAMPZ = and + * Z-register are used as page address. When writing the Program memory, = the + * RAMPZ and Z-register are used as page or word address, and the R1:R0 + * register pair is used as data(1). When setting the Boot Loader Lock bi= ts, + * the R1:R0 register pair is used as data. Refer to the device documenta= tion + * for detailed description of SPM usage. This instruction can address the + * entire Program memory. The SPM instruction is not available in all de= vices. + * Refer to the device specific instruction set summary. Note: 1. R1 + * determines the instruction high byte, and R0 determines the instructio= n low + * byte. + */ +static bool trans_SPM(DisasContext *ctx, arg_SPM *a) +{ + /* TODO */ + if (!avr_have_feature(ctx, AVR_FEATURE_SPM)) { + return true; + } + + return true; +} + + +static bool trans_SPMX(DisasContext *ctx, arg_SPMX *a) +{ + /* TODO */ + if (!avr_have_feature(ctx, AVR_FEATURE_SPMX)) { + return true; + } + + return true; +} + + +/* + * Loads data from the I/O Space (Ports, Timers, Configuration Registers, + * etc.) into register Rd in the Register File. + */ +static bool trans_IN(DisasContext *ctx, arg_IN *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv port =3D tcg_const_i32(a->imm); + + gen_helper_inb(Rd, cpu_env, port); + + tcg_temp_free_i32(port); + + return true; +} + + +/* + * Stores data from register Rr in the Register File to I/O Space (Ports, + * Timers, Configuration Registers, etc.). + */ +static bool trans_OUT(DisasContext *ctx, arg_OUT *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv port =3D tcg_const_i32(a->imm); + + gen_helper_outb(cpu_env, port, Rd); + + tcg_temp_free_i32(port); + + return true; +} + + +/* + * This instruction stores the contents of register Rr on the STACK. The + * Stack Pointer is post-decremented by 1 after the PUSH. This instructi= on is + * not available in all devices. Refer to the device specific instruction= set + * summary. + */ +static bool trans_PUSH(DisasContext *ctx, arg_PUSH *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + + gen_data_store(ctx, Rd, cpu_sp); + tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); + + return true; +} + + +/* + * This instruction loads register Rd with a byte from the STACK. The Sta= ck + * Pointer is pre-incremented by 1 before the POP. This instruction is n= ot + * available in all devices. Refer to the device specific instruction set + * summary. + */ +static bool trans_POP(DisasContext *ctx, arg_POP *a) +{ + /* + * Using a temp to work around some strange behaviour: + * tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); + * gen_data_load(ctx, Rd, cpu_sp); + * seems to cause the add to happen twice. + * This doesn't happen if either the add or the load is removed. + */ + TCGv t1 =3D tcg_temp_new_i32(); + TCGv Rd =3D cpu_r[a->rd]; + + tcg_gen_addi_tl(t1, cpu_sp, 1); + gen_data_load(ctx, Rd, t1); + tcg_gen_mov_tl(cpu_sp, t1); + + return true; +} + + +/* + * Exchanges one byte indirect between register and data space. The data + * location is pointed to by the Z (16 bits) Pointer Register in the Regi= ster + * File. Memory access is limited to the current data segment of 64KB. To + * access another data segment in devices with more than 64KB data space,= the + * RAMPZ in register in the I/O area has to be changed. The Z-pointer Re= gister + * is left unchanged by the operation. This instruction is especially sui= ted + * for writing/reading status bits stored in SRAM. + */ +static bool trans_XCH(DisasContext *ctx, arg_XCH *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) { + return true; + } + + TCGv Rd =3D cpu_r[a->rd]; + TCGv t0 =3D tcg_temp_new_i32(); + TCGv addr =3D gen_get_zaddr(); + + gen_data_load(ctx, t0, addr); + gen_data_store(ctx, Rd, addr); + tcg_gen_mov_tl(Rd, t0); + + tcg_temp_free_i32(t0); + tcg_temp_free_i32(addr); + + return true; +} + + +/* + * Load one byte indirect from data space to register and set bits in data + * space specified by the register. The instruction can only be used towa= rds + * internal SRAM. The data location is pointed to by the Z (16 bits) Poi= nter + * Register in the Register File. Memory access is limited to the current= data + * segment of 64KB. To access another data segment in devices with more t= han + * 64KB data space, the RAMPZ in register in the I/O area has to be chang= ed. + * The Z-pointer Register is left unchanged by the operation. This instru= ction + * is especially suited for setting status bits stored in SRAM. + */ +static bool trans_LAS(DisasContext *ctx, arg_LAS *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) { + return true; + } + + TCGv Rr =3D cpu_r[a->rd]; + TCGv addr =3D gen_get_zaddr(); + TCGv t0 =3D tcg_temp_new_i32(); + TCGv t1 =3D tcg_temp_new_i32(); + + gen_data_load(ctx, t0, addr); /* t0 =3D mem[addr] */ + tcg_gen_or_tl(t1, t0, Rr); + + tcg_gen_mov_tl(Rr, t0); /* Rr =3D t0 */ + gen_data_store(ctx, t1, addr); /* mem[addr] =3D t1 */ + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(addr); + + return true; +} + + +/* + * Load one byte indirect from data space to register and stores and clear + * the bits in data space specified by the register. The instruction can + * only be used towards internal SRAM. The data location is pointed to by + * the Z (16 bits) Pointer Register in the Register File. Memory access is + * limited to the current data segment of 64KB. To access another data + * segment in devices with more than 64KB data space, the RAMPZ in regist= er + * in the I/O area has to be changed. The Z-pointer Register is left + * unchanged by the operation. This instruction is especially suited for + * clearing status bits stored in SRAM. + */ +static bool trans_LAC(DisasContext *ctx, arg_LAC *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) { + return true; + } + + TCGv Rr =3D cpu_r[a->rd]; + TCGv addr =3D gen_get_zaddr(); + TCGv t0 =3D tcg_temp_new_i32(); + TCGv t1 =3D tcg_temp_new_i32(); + + gen_data_load(ctx, t0, addr); /* t0 =3D mem[addr] */ + /* t1 =3D t0 & (0xff - Rr) =3D t0 and ~Rr */ + tcg_gen_andc_tl(t1, t0, Rr); + + tcg_gen_mov_tl(Rr, t0); /* Rr =3D t0 */ + gen_data_store(ctx, t1, addr); /* mem[addr] =3D t1 */ + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(addr); + + return true; +} + + +/* + * Load one byte indirect from data space to register and toggles bits in + * the data space specified by the register. The instruction can only be= used + * towards SRAM. The data location is pointed to by the Z (16 bits) Poin= ter + * Register in the Register File. Memory access is limited to the current= data + * segment of 64KB. To access another data segment in devices with more t= han + * 64KB data space, the RAMPZ in register in the I/O area has to be chang= ed. + * The Z-pointer Register is left unchanged by the operation. This instru= ction + * is especially suited for changing status bits stored in SRAM. + */ +static bool trans_LAT(DisasContext *ctx, arg_LAT *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) { + return true; + } + + TCGv Rd =3D cpu_r[a->rd]; + TCGv addr =3D gen_get_zaddr(); + TCGv t0 =3D tcg_temp_new_i32(); + TCGv t1 =3D tcg_temp_new_i32(); + + gen_data_load(ctx, t0, addr); /* t0 =3D mem[addr] */ + tcg_gen_xor_tl(t1, t0, Rd); + + tcg_gen_mov_tl(Rd, t0); /* Rd =3D t0 */ + gen_data_store(ctx, t1, addr); /* mem[addr] =3D t1 */ + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(addr); + + return true; +} + + +/* + * Shifts all bits in Rd one place to the right. Bit 7 is cleared. Bit 0 = is + * loaded into the C Flag of the SREG. This operation effectively divides= an + * unsigned value by two. The C Flag can be used to round the result. + */ +static bool trans_LSR(DisasContext *ctx, arg_LSR *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + + tcg_gen_andi_tl(cpu_Cf, Rd, 1); + + tcg_gen_shri_tl(Rd, Rd, 1); + + tcg_gen_mov_tl(cpu_Zf, Rd); + tcg_gen_movi_tl(cpu_Nf, 0); + tcg_gen_mov_tl(cpu_Vf, cpu_Cf); + tcg_gen_mov_tl(cpu_Sf, cpu_Vf); + + return true; +} + + +/* + * Shifts all bits in Rd one place to the right. The C Flag is shifted in= to + * bit 7 of Rd. Bit 0 is shifted into the C Flag. This operation, combin= ed + * with ASR, effectively divides multi-byte signed values by two. Combine= d with + * LSR it effectively divides multi-byte unsigned values by two. The Carr= y Flag + * can be used to round the result. + */ +static bool trans_ROR(DisasContext *ctx, arg_ROR *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv t0 =3D tcg_temp_new_i32(); + + tcg_gen_shli_tl(t0, cpu_Cf, 7); + tcg_gen_andi_tl(cpu_Cf, Rd, 1); + tcg_gen_shri_tl(Rd, Rd, 1); + tcg_gen_or_tl(Rd, Rd, t0); + + gen_rshift_ZNVSf(Rd); + + tcg_temp_free_i32(t0); + + return true; +} + + +/* + * Shifts all bits in Rd one place to the right. Bit 7 is held constant. = Bit 0 + * is loaded into the C Flag of the SREG. This operation effectively divi= des a + * signed value by two without changing its sign. The Carry Flag can be u= sed to + * round the result. + */ +static bool trans_ASR(DisasContext *ctx, arg_ASR *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv t0 =3D tcg_temp_new_i32(); + + /* Cf */ + tcg_gen_andi_tl(cpu_Cf, Rd, 1); /* Cf =3D Rd(0) */ + + /* op */ + tcg_gen_andi_tl(t0, Rd, 0x80); /* Rd =3D (Rd & 0x80) | (Rd >> 1) */ + tcg_gen_shri_tl(Rd, Rd, 1); + tcg_gen_or_tl(Rd, Rd, t0); + + gen_rshift_ZNVSf(Rd); + + tcg_temp_free_i32(t0); + + return true; +} + + +/* + * Swaps high and low nibbles in a register. + */ +static bool trans_SWAP(DisasContext *ctx, arg_SWAP *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv t0 =3D tcg_temp_new_i32(); + TCGv t1 =3D tcg_temp_new_i32(); + + tcg_gen_andi_tl(t0, Rd, 0x0f); + tcg_gen_shli_tl(t0, t0, 4); + tcg_gen_andi_tl(t1, Rd, 0xf0); + tcg_gen_shri_tl(t1, t1, 4); + tcg_gen_or_tl(Rd, t0, t1); + + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t0); + + return true; +} + + +/* + * Sets a specified bit in an I/O Register. This instruction operates on + * the lower 32 I/O Registers -- addresses 0-31. + */ +static bool trans_SBI(DisasContext *ctx, arg_SBI *a) +{ + TCGv data =3D tcg_temp_new_i32(); + TCGv port =3D tcg_const_i32(a->reg); + + gen_helper_inb(data, cpu_env, port); + tcg_gen_ori_tl(data, data, 1 << a->bit); + gen_helper_outb(cpu_env, port, data); + + tcg_temp_free_i32(port); + tcg_temp_free_i32(data); + + return true; +} + + +/* + * Clears a specified bit in an I/O Register. This instruction operates on + * the lower 32 I/O Registers -- addresses 0-31. + */ +static bool trans_CBI(DisasContext *ctx, arg_CBI *a) +{ + TCGv data =3D tcg_temp_new_i32(); + TCGv port =3D tcg_const_i32(a->reg); + + gen_helper_inb(data, cpu_env, port); + tcg_gen_andi_tl(data, data, ~(1 << a->bit)); + gen_helper_outb(cpu_env, port, data); + + tcg_temp_free_i32(data); + tcg_temp_free_i32(port); + + return true; +} + + +/* + * Stores bit b from Rd to the T Flag in SREG (Status Register). + */ +static bool trans_BST(DisasContext *ctx, arg_BST *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + + tcg_gen_andi_tl(cpu_Tf, Rd, 1 << a->bit); + tcg_gen_shri_tl(cpu_Tf, cpu_Tf, a->bit); + + return true; +} + + +/* + * Copies the T Flag in the SREG (Status Register) to bit b in register R= d. + */ +static bool trans_BLD(DisasContext *ctx, arg_BLD *a) +{ + TCGv Rd =3D cpu_r[a->rd]; + TCGv t1 =3D tcg_temp_new_i32(); + + tcg_gen_andi_tl(Rd, Rd, ~(1u << a->bit)); /* clear bit */ + tcg_gen_shli_tl(t1, cpu_Tf, a->bit); /* create mask */ + tcg_gen_or_tl(Rd, Rd, t1); + + tcg_temp_free_i32(t1); + + return true; +} + + +/* + * Sets a single Flag or bit in SREG. + */ +static bool trans_BSET(DisasContext *ctx, arg_BSET *a) +{ + switch (a->bit) { + case 0x00: + tcg_gen_movi_tl(cpu_Cf, 0x01); + break; + case 0x01: + tcg_gen_movi_tl(cpu_Zf, 0x00); + break; + case 0x02: + tcg_gen_movi_tl(cpu_Nf, 0x01); + break; + case 0x03: + tcg_gen_movi_tl(cpu_Vf, 0x01); + break; + case 0x04: + tcg_gen_movi_tl(cpu_Sf, 0x01); + break; + case 0x05: + tcg_gen_movi_tl(cpu_Hf, 0x01); + break; + case 0x06: + tcg_gen_movi_tl(cpu_Tf, 0x01); + break; + case 0x07: + tcg_gen_movi_tl(cpu_If, 0x01); + break; + } + + return true; +} + + +/* + * Clears a single Flag in SREG. + */ +static bool trans_BCLR(DisasContext *ctx, arg_BCLR *a) +{ + switch (a->bit) { + case 0x00: + tcg_gen_movi_tl(cpu_Cf, 0x00); + break; + case 0x01: + tcg_gen_movi_tl(cpu_Zf, 0x01); + break; + case 0x02: + tcg_gen_movi_tl(cpu_Nf, 0x00); + break; + case 0x03: + tcg_gen_movi_tl(cpu_Vf, 0x00); + break; + case 0x04: + tcg_gen_movi_tl(cpu_Sf, 0x00); + break; + case 0x05: + tcg_gen_movi_tl(cpu_Hf, 0x00); + break; + case 0x06: + tcg_gen_movi_tl(cpu_Tf, 0x00); + break; + case 0x07: + tcg_gen_movi_tl(cpu_If, 0x00); + break; + } + + return true; +} --=20 2.17.2 (Apple Git-113) From nobody Tue May 7 17:09:40 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1571074994; cv=none; d=zoho.com; s=zohoarc; b=Ozy4TGCa9140cD1DIfKlc4RitxPl3uPu9+MzIXyabzXTSglQuQBkZdw/329yBCb6j6365nXkS4vv77dVVtQKK+KY7M19riN2mDbXdvFgxFsQjZGMfdGm/89pzYVDtr+QnajV8n98lX7x5035H0Y47MRfN/AgA+SYrgwcAFUPPag= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1571074994; h=Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:Message-ID:References:Sender:Subject:To; bh=BGvkLFU66e7VXKZNz1ZYyyXcitOZp+YBucUP/E/zH5s=; b=hHvOWd7RJOoPDub7wMw4zggaXxqVqlBXhlUUJ6TBnIh/ta8eJVTx2qH79OC3cwPV/6kFtQr7L0c9OLSYyf6wFQuZeJtfzKWVskFXi07Ybuk3JNaPoa7LmQ3HqwIIESouzedrMAA8c8+M1ncnbNqhJDR7gn3B0qP4ks05g7LZzl8= ARC-Authentication-Results: i=1; mx.zoho.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1571074994110831.6900663682505; Mon, 14 Oct 2019 10:43:14 -0700 (PDT) Received: from localhost ([::1]:54818 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iK4NF-0003Lh-2r for importer@patchew.org; Mon, 14 Oct 2019 13:43:13 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:39837) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iK348-0006IB-QQ for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:26 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iK347-0007VR-Ce for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:24 -0400 Received: from mail-wm1-x341.google.com ([2a00:1450:4864:20::341]:39746) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1iK347-0007VE-6F for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:23 -0400 Received: by mail-wm1-x341.google.com with SMTP id v17so17336501wml.4 for ; Mon, 14 Oct 2019 09:19:23 -0700 (PDT) Received: from 8c859074c0ff.ant.amazon.com.com (bzq-79-178-11-117.red.bezeqint.net. [79.178.11.117]) by smtp.gmail.com with ESMTPSA id c132sm28050861wme.27.2019.10.14.09.19.19 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 14 Oct 2019 09:19:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=BGvkLFU66e7VXKZNz1ZYyyXcitOZp+YBucUP/E/zH5s=; b=YZp0ZYxT3aQVWV64jYOLMgPtF/1gRqIwgM6sdAtsoWFRFnvBZB7zLL/tjkoWEgTArL n+6Ypquk5KRjn5CPw4aj4NS9yxkvG3m6UHNsXFgtWpMGNWhkPIcmWV5aDhhQz3nt4ZcP Rck3HFA/LSEz+1LkU0aTNzF0OY8aP5G3pU24xOHOP/mVe9bAtBwle0Up67GKI9KaCG9x wTWNkknAt3qYd+3zjW++i8VdL+G0+mEWZoeJrHYM0vy72mzoimyXh4624K52YonSKis4 Qu5VZpoa5cp+/gFJ1UMLSu9fsZVnRIkB4bsbKOdUCI7PovxaQLHzPAhG8b1udmLO+0AQ NRYA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=BGvkLFU66e7VXKZNz1ZYyyXcitOZp+YBucUP/E/zH5s=; b=RRlkZApJ6oJjrD0WVNqSIASzKNAhkmJdPyUcMrVwQHbYEgJJjbCEP8W3l8NdNecNYK ozeShzTJn4gn3BSBfCoDLVphfyKRyUNv3NN7+F2L6Ls0iszIREH1FEOfHjZyLQFvVvYF ZVPxuRZ8l3J80xCkps31kvUHVY1MHMU79kTQpzSRrFTaEuBQ7mQJoTdjTxNoXsP669cT hOBtBpi57Wx5uSMjkGYU1vH2wwGwFEF7YLwpNNowGGiffi/E3QnKc2ybz31ayW9fhMf3 D+Yfcy1GajAW3fwfeeweI+uhxKqLrlGzKaFTtnSeFc6kiaKCTHSgAjxzkYNLkvYT4jT7 0t5A== X-Gm-Message-State: APjAAAXiyZhkJCisk/dEaYrmuDYfqELFzIEfXNYYwkXDZh0icVtvvpMg H4Is3P2SAiMl1LnC4rjvLqQ4fjPpB1w= X-Google-Smtp-Source: APXvYqxfOFEXSBGctIZ49QVBqGTGlhMitpEBeWZK5IWrFqTNhNWnNFfvTgO9RqRh7JwAkYQ+m5966Q== X-Received: by 2002:a1c:9ecf:: with SMTP id h198mr15494414wme.45.1571069961733; Mon, 14 Oct 2019 09:19:21 -0700 (PDT) From: Michael Rolnik To: qemu-devel@nongnu.org Subject: [PATCH v32 08/13] target/avr: Add instruction translation - MCU Control Instructions Date: Mon, 14 Oct 2019 19:18:38 +0300 Message-Id: <20191014161843.84845-9-mrolnik@gmail.com> X-Mailer: git-send-email 2.17.2 (Apple Git-113) In-Reply-To: <20191014161843.84845-1-mrolnik@gmail.com> References: <20191014161843.84845-1-mrolnik@gmail.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::341 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: thuth@redhat.com, Michael Rolnik , richard.henderson@linaro.org, dovgaluk@ispras.ru, imammedo@redhat.com, philmd@redhat.com, aleksandar.m.mail@gmail.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This includes: - BREAK - NOP - SLEEP - WDR Signed-off-by: Michael Rolnik --- target/avr/translate.c | 174 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) diff --git a/target/avr/translate.c b/target/avr/translate.c index 19540634df..21ba6004ee 100644 --- a/target/avr/translate.c +++ b/target/avr/translate.c @@ -368,6 +368,115 @@ static bool trans_ADC(DisasContext *ctx, arg_ADC *a) } =20 =20 +static void gen_jmp_ez(DisasContext *ctx) +{ + tcg_gen_deposit_tl(cpu_pc, cpu_r[30], cpu_r[31], 8, 8); + tcg_gen_or_tl(cpu_pc, cpu_pc, cpu_eind); + ctx->bstate =3D DISAS_LOOKUP; +} + + +static void gen_jmp_z(DisasContext *ctx) +{ + tcg_gen_deposit_tl(cpu_pc, cpu_r[30], cpu_r[31], 8, 8); + ctx->bstate =3D DISAS_LOOKUP; +} + + +/* + * in the gen_set_addr & gen_get_addr functions + * H assumed to be in 0x00ff0000 format + * M assumed to be in 0x000000ff format + * L assumed to be in 0x000000ff format + */ +static void gen_set_addr(TCGv addr, TCGv H, TCGv M, TCGv L) +{ + + tcg_gen_andi_tl(L, addr, 0x000000ff); + + tcg_gen_andi_tl(M, addr, 0x0000ff00); + tcg_gen_shri_tl(M, M, 8); + + tcg_gen_andi_tl(H, addr, 0x00ff0000); +} + + +static void gen_set_xaddr(TCGv addr) +{ + gen_set_addr(addr, cpu_rampX, cpu_r[27], cpu_r[26]); +} + + +static void gen_set_yaddr(TCGv addr) +{ + gen_set_addr(addr, cpu_rampY, cpu_r[29], cpu_r[28]); +} + + +static void gen_set_zaddr(TCGv addr) +{ + gen_set_addr(addr, cpu_rampZ, cpu_r[31], cpu_r[30]); +} + + +static TCGv gen_get_addr(TCGv H, TCGv M, TCGv L) +{ + TCGv addr =3D tcg_temp_new_i32(); + + tcg_gen_deposit_tl(addr, M, H, 8, 8); + tcg_gen_deposit_tl(addr, L, addr, 8, 16); + + return addr; +} + + +static TCGv gen_get_xaddr(void) +{ + return gen_get_addr(cpu_rampX, cpu_r[27], cpu_r[26]); +} + + +static TCGv gen_get_yaddr(void) +{ + return gen_get_addr(cpu_rampY, cpu_r[29], cpu_r[28]); +} + + +static TCGv gen_get_zaddr(void) +{ + return gen_get_addr(cpu_rampZ, cpu_r[31], cpu_r[30]); +} + + +/* + * Load one byte indirect from data space to register and stores an clear + * the bits in data space specified by the register. The instruction can = only + * be used towards internal SRAM. The data location is pointed to by the= Z (16 + * bits) Pointer Register in the Register File. Memory access is limited = to the + * current data segment of 64KB. To access another data segment in device= s with + * more than 64KB data space, the RAMPZ in register in the I/O area has t= o be + * changed. The Z-pointer Register is left unchanged by the operation. T= his + * instruction is especially suited for clearing status bits stored in SR= AM. + */ +static void gen_data_store(DisasContext *ctx, TCGv data, TCGv addr) +{ + if (ctx->tb->flags & TB_FLAGS_FULL_ACCESS) { + gen_helper_fullwr(cpu_env, data, addr); + } else { + tcg_gen_qemu_st8(data, addr, MMU_DATA_IDX); /* mem[addr] =3D data = */ + } +} + +static void gen_data_load(DisasContext *ctx, TCGv data, TCGv addr) +{ + if (ctx->tb->flags & TB_FLAGS_FULL_ACCESS) { + gen_helper_fullrd(data, cpu_env, addr); + } else { + tcg_gen_qemu_ld8u(data, addr, MMU_DATA_IDX); /* data =3D mem[addr]= */ + } +} + + /* * Subtracts an immediate value (0-63) from a register pair and places the * result in the register pair. This instruction operates on the upper fo= ur @@ -2606,3 +2715,68 @@ static bool trans_BCLR(DisasContext *ctx, arg_BCLR *= a) =20 return true; } + + +/* + * The BREAK instruction is used by the On-chip Debug system, and is + * normally not used in the application software. When the BREAK instruct= ion is + * executed, the AVR CPU is set in the Stopped Mode. This gives the On-ch= ip + * Debugger access to internal resources. If any Lock bits are set, or e= ither + * the JTAGEN or OCDEN Fuses are unprogrammed, the CPU will treat the BRE= AK + * instruction as a NOP and will not enter the Stopped mode. This instru= ction + * is not available in all devices. Refer to the device specific instruct= ion + * set summary. + */ +static bool trans_BREAK(DisasContext *ctx, arg_BREAK *a) +{ + if (!avr_have_feature(ctx, AVR_FEATURE_BREAK)) { + return true; + } + +#ifdef BREAKPOINT_ON_BREAK + tcg_gen_movi_tl(cpu_pc, ctx->npc - 1); + gen_helper_debug(cpu_env); + ctx->bstate =3D DISAS_EXIT; +#else + /* NOP */ +#endif + + return true; +} + + +/* + * This instruction performs a single cycle No Operation. + */ +static bool trans_NOP(DisasContext *ctx, arg_NOP *a) +{ + + /* NOP */ + + return true; +} + + +/* + * This instruction sets the circuit in sleep mode defined by the MCU + * Control Register. + */ +static bool trans_SLEEP(DisasContext *ctx, arg_SLEEP *a) +{ + gen_helper_sleep(cpu_env); + ctx->bstate =3D DISAS_NORETURN; + return true; +} + + +/* + * This instruction resets the Watchdog Timer. This instruction must be + * executed within a limited time given by the WD prescaler. See the Watc= hdog + * Timer hardware specification. + */ +static bool trans_WDR(DisasContext *ctx, arg_WDR *a) +{ + gen_helper_wdr(cpu_env); + + return true; +} --=20 2.17.2 (Apple Git-113) From nobody Tue May 7 17:09:40 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1571073177; cv=none; d=zoho.com; s=zohoarc; b=VztAPKQ9L2IjFVnAKJ3BZWLNHub2kSewySQG5JVadzdT8T8v9o+oLhfMQd5mHVO3XlI/s6nOkyX/lvjK9T1GLLME3UmcBCRj5lq+3rnrgTdfMS1dHeaIlC0OlfdjFNwZKXzEJI5HDcZZ7XsWYS4vbbSG6QhbhInzPKrW24WqYLE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1571073177; h=Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:Message-ID:References:Sender:Subject:To; bh=EnvztjGlFmT9NSv8f9UKg3YpZOQWR8+pk98JNeLeHzo=; b=NBhCu7i1kCG6yRifCLcHGvdQfkAbjX+fV3XOnmLS1srO4u7c8U67D2PBvmaC72NYlNdx4/kHlD3jDxFZobN90E7HxcDqHcTumbNAxR1dRateCiCNZ2SJIwf7A5eMi42W/VucUk1NwaPZ98868ScdnjTgerexv9F3aiGQpDXSvI8= ARC-Authentication-Results: i=1; mx.zoho.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1571073177235937.7334307878151; Mon, 14 Oct 2019 10:12:57 -0700 (PDT) Received: from localhost ([::1]:54170 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iK3tv-0007KT-Fi for importer@patchew.org; Mon, 14 Oct 2019 13:12:55 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:39854) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iK34B-0006LA-1L for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:28 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iK349-0007W7-64 for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:26 -0400 Received: from mail-wm1-x343.google.com ([2a00:1450:4864:20::343]:33966) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1iK348-0007Vy-VH for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:25 -0400 Received: by mail-wm1-x343.google.com with SMTP id y135so360493wmc.1 for ; Mon, 14 Oct 2019 09:19:24 -0700 (PDT) Received: from 8c859074c0ff.ant.amazon.com.com (bzq-79-178-11-117.red.bezeqint.net. [79.178.11.117]) by smtp.gmail.com with ESMTPSA id c132sm28050861wme.27.2019.10.14.09.19.21 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 14 Oct 2019 09:19:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=EnvztjGlFmT9NSv8f9UKg3YpZOQWR8+pk98JNeLeHzo=; b=C8Yaxs1lpSWTw8Xk/QN/S/gGuleQOw1Bruf5kKVIQNTXZMEyyGo8JXBzylNXBjGELd zKFbSFSrhqsNJOGyaC4FCyHg+EenITii6aMll4EhNpreyo9N0zcLdoRGU7/5eGUc0fLI CpxVaPWOjjphm6jc2Ut4VKqDRKVV7PvQrvXZTJKJL3ZnW9io+Uf3/cb65B/tj7QqIey1 r3YJMbfQW8TBfZW24gd7Wg+hTdzU3jwiYtcFdUuEKXumHuo+6cZyOY4kRvCS2OSDz3dj 4cIQlRseyKsAmOPZS1/ZSO9b2IojJnRcMTV6f/Cz+PqdjxgF2fXFnMKGqRx5uQdX8HFT xuwA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=EnvztjGlFmT9NSv8f9UKg3YpZOQWR8+pk98JNeLeHzo=; b=YBGNuJ+dPH6jdkVwk2Eq5CyHU5WA+sbJzEufnR5ehp8Bdf7VXF+mbEg9Af8rP/taiG hq9mu9ISkOe7URFBIrPCOMFCYQZy7Ls2Y/Ej/FG0mx4QmVd75FGgYA/7nS2Parl3Zw+7 4JT9j8lSwEbnQGgZ8fHcXoRJXBWdWzi7DqSuFJKKcHQ9hlfrhIHVQRVltNwSNZW2MaSe KGDju9EgnJ4+pGcUWbG8BRQ9E0szfQH76TPrfjSAw45y38l+qHgPnu3BAOW4/Wl/P/a+ RwMyNxsjHkTbeJz96sba3IGAXzxrfKdsYTwYS6IbYTR2GaHbRzJRcJWR6uUEvFO/fIpG 0lcw== X-Gm-Message-State: APjAAAUQwcDPUOuhR/1KpVXT0xPLKbO9sH9h8APwj4BVJ+x0HWJj3n4L Pl/Y/I4r8PKDupjS7080+20wGM38Jck= X-Google-Smtp-Source: APXvYqzeWv0oVB3j+Wq6qh3cKXIZgIpNw9YvSSrSNRDEv2h/NG2fRgwkmlhjuyR1xoVFdrIObmgbTQ== X-Received: by 2002:a1c:8157:: with SMTP id c84mr15298023wmd.56.1571069963595; Mon, 14 Oct 2019 09:19:23 -0700 (PDT) From: Michael Rolnik To: qemu-devel@nongnu.org Subject: [PATCH v32 09/13] target/avr: Add instruction translation - CPU main translation function Date: Mon, 14 Oct 2019 19:18:39 +0300 Message-Id: <20191014161843.84845-10-mrolnik@gmail.com> X-Mailer: git-send-email 2.17.2 (Apple Git-113) In-Reply-To: <20191014161843.84845-1-mrolnik@gmail.com> References: <20191014161843.84845-1-mrolnik@gmail.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::343 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: thuth@redhat.com, Michael Rolnik , richard.henderson@linaro.org, dovgaluk@ispras.ru, imammedo@redhat.com, philmd@redhat.com, aleksandar.m.mail@gmail.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Co-developed-by: Richard Henderson Co-developed-by: Michael Rolnik Signed-off-by: Michael Rolnik --- target/avr/translate.c | 234 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 234 insertions(+) diff --git a/target/avr/translate.c b/target/avr/translate.c index 21ba6004ee..6d4a023ff9 100644 --- a/target/avr/translate.c +++ b/target/avr/translate.c @@ -2780,3 +2780,237 @@ static bool trans_WDR(DisasContext *ctx, arg_WDR *a) =20 return true; } + + +void avr_cpu_tcg_init(void) +{ + int i; + +#define AVR_REG_OFFS(x) offsetof(CPUAVRState, x) + cpu_pc =3D tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(pc_w), "pc"); + cpu_Cf =3D tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregC), "Cf"); + cpu_Zf =3D tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregZ), "Zf"); + cpu_Nf =3D tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregN), "Nf"); + cpu_Vf =3D tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregV), "Vf"); + cpu_Sf =3D tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregS), "Sf"); + cpu_Hf =3D tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregH), "Hf"); + cpu_Tf =3D tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregT), "Tf"); + cpu_If =3D tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregI), "If"); + cpu_rampD =3D tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampD), "ra= mpD"); + cpu_rampX =3D tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampX), "ra= mpX"); + cpu_rampY =3D tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampY), "ra= mpY"); + cpu_rampZ =3D tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampZ), "ra= mpZ"); + cpu_eind =3D tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(eind), "eind= "); + cpu_sp =3D tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sp), "sp"); + cpu_skip =3D tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(skip), "skip= "); + + for (i =3D 0; i < NO_CPU_REGISTERS; i++) { + cpu_r[i] =3D tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(r[i]), + reg_names[i]); + } +#undef AVR_REG_OFFS +} + +static void translate(DisasContext *ctx) +{ + uint32_t opcode =3D next_word(ctx); + + if (!decode_insn(ctx, opcode)) { + gen_helper_unsupported(cpu_env); + ctx->bstate =3D DISAS_NORETURN; + } +} + +/* Standardize the cpu_skip condition to NE. */ +static bool canonicalize_skip(DisasContext *ctx) +{ + switch (ctx->skip_cond) { + case TCG_COND_NEVER: + /* Normal case: cpu_skip is known to be false. */ + return false; + + case TCG_COND_ALWAYS: + /* + * Breakpoint case: cpu_skip is known to be true, via TB_FLAGS_SKI= P. + * The breakpoint is on the instruction being skipped, at the start + * of the TranslationBlock. No need to update. + */ + return false; + + case TCG_COND_NE: + if (ctx->skip_var1 =3D=3D NULL) { + tcg_gen_mov_tl(cpu_skip, ctx->skip_var0); + } else { + tcg_gen_xor_tl(cpu_skip, ctx->skip_var0, ctx->skip_var1); + ctx->skip_var1 =3D NULL; + } + break; + + default: + /* Convert to a NE condition vs 0. */ + if (ctx->skip_var1 =3D=3D NULL) { + tcg_gen_setcondi_tl(ctx->skip_cond, cpu_skip, ctx->skip_var0, = 0); + } else { + tcg_gen_setcond_tl(ctx->skip_cond, cpu_skip, + ctx->skip_var0, ctx->skip_var1); + ctx->skip_var1 =3D NULL; + } + ctx->skip_cond =3D TCG_COND_NE; + break; + } + if (ctx->free_skip_var0) { + tcg_temp_free(ctx->skip_var0); + ctx->free_skip_var0 =3D false; + } + ctx->skip_var0 =3D cpu_skip; + return true; +} + +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_ins= ns) +{ + CPUAVRState *env =3D cs->env_ptr; + DisasContext ctx =3D { + .tb =3D tb, + .cs =3D cs, + .env =3D env, + .memidx =3D 0, + .bstate =3D DISAS_NEXT, + .skip_cond =3D TCG_COND_NEVER, + .singlestep =3D cs->singlestep_enabled, + }; + target_ulong pc_start =3D tb->pc / 2; + int num_insns =3D 0; + + if (tb->flags & TB_FLAGS_FULL_ACCESS) { + /* + * This flag is set by ST/LD instruction we will regenerate it ONLY + * with mem/cpu memory access instead of mem access + */ + max_insns =3D 1; + } + if (ctx.singlestep) { + max_insns =3D 1; + } + + gen_tb_start(tb); + + ctx.npc =3D pc_start; + if (tb->flags & TB_FLAGS_SKIP) { + ctx.skip_cond =3D TCG_COND_ALWAYS; + ctx.skip_var0 =3D cpu_skip; + } + + do { + TCGLabel *skip_label =3D NULL; + + /* translate current instruction */ + tcg_gen_insn_start(ctx.npc); + num_insns++; + + /* + * this is due to some strange GDB behavior + * let's assume main has address 0x100 + * b main - sets breakpoint at address 0x00000100 (code) + * b *0x100 - sets breakpoint at address 0x00800100 (data) + */ + if (unlikely(!ctx.singlestep && + (cpu_breakpoint_test(cs, OFFSET_CODE + ctx.npc * 2, BP_ANY= ) || + cpu_breakpoint_test(cs, OFFSET_DATA + ctx.npc * 2, BP_ANY= )))) { + canonicalize_skip(&ctx); + tcg_gen_movi_tl(cpu_pc, ctx.npc); + gen_helper_debug(cpu_env); + goto done_generating; + } + + /* Conditionally skip the next instruction, if indicated. */ + if (ctx.skip_cond !=3D TCG_COND_NEVER) { + skip_label =3D gen_new_label(); + if (ctx.skip_var0 =3D=3D cpu_skip) { + /* + * Copy cpu_skip so that we may zero it before the branch. + * This ensures that cpu_skip is non-zero after the label + * if and only if the skipped insn itself sets a skip. + */ + ctx.free_skip_var0 =3D true; + ctx.skip_var0 =3D tcg_temp_new(); + tcg_gen_mov_tl(ctx.skip_var0, cpu_skip); + tcg_gen_movi_tl(cpu_skip, 0); + } + if (ctx.skip_var1 =3D=3D NULL) { + tcg_gen_brcondi_tl(ctx.skip_cond, ctx.skip_var0, 0, skip_l= abel); + } else { + tcg_gen_brcond_tl(ctx.skip_cond, ctx.skip_var0, + ctx.skip_var1, skip_label); + ctx.skip_var1 =3D NULL; + } + if (ctx.free_skip_var0) { + tcg_temp_free(ctx.skip_var0); + ctx.free_skip_var0 =3D false; + } + ctx.skip_cond =3D TCG_COND_NEVER; + ctx.skip_var0 =3D NULL; + } + + translate(&ctx); + + if (skip_label) { + canonicalize_skip(&ctx); + gen_set_label(skip_label); + if (ctx.bstate =3D=3D DISAS_NORETURN) { + ctx.bstate =3D DISAS_CHAIN; + } + } + } while (ctx.bstate =3D=3D DISAS_NEXT + && num_insns < max_insns + && (ctx.npc - pc_start) * 2 < TARGET_PAGE_SIZE - 4 + && !tcg_op_buf_full()); + + if (tb->cflags & CF_LAST_IO) { + gen_io_end(); + } + + bool nonconst_skip =3D canonicalize_skip(&ctx); + + switch (ctx.bstate) { + case DISAS_NORETURN: + assert(!nonconst_skip); + break; + case DISAS_NEXT: + case DISAS_TOO_MANY: + case DISAS_CHAIN: + if (!nonconst_skip) { + /* Note gen_goto_tb checks singlestep. */ + gen_goto_tb(&ctx, 1, ctx.npc); + break; + } + tcg_gen_movi_tl(cpu_pc, ctx.npc); + /* fall through */ + case DISAS_LOOKUP: + if (!ctx.singlestep) { + tcg_gen_lookup_and_goto_ptr(); + break; + } + /* fall through */ + case DISAS_EXIT: + if (ctx.singlestep) { + gen_helper_debug(cpu_env); + } else { + tcg_gen_exit_tb(NULL, 0); + } + break; + default: + g_assert_not_reached(); + } + +done_generating: + gen_tb_end(tb, num_insns); + + tb->size =3D (ctx.npc - pc_start) * 2; + tb->icount =3D num_insns; +} + +void restore_state_to_opc(CPUAVRState *env, TranslationBlock *tb, + target_ulong *data) +{ + env->pc_w =3D data[0]; +} --=20 2.17.2 (Apple Git-113) From nobody Tue May 7 17:09:40 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1571073307; cv=none; d=zoho.com; s=zohoarc; b=RbOTBT4w25/qFHRbwPkSTI8fglKLpMbtWhMSH2MqbYd65yyPW1Uke+7wj9lBd3tF1W3PiJeCF1/OXFXuUsP3xcLhmF9jcELzVPt5f7uKl8lLXgIYxJTtJNksdfLX2IaMuJeJ0F2XOuK3IbMMZuZZOOr2Q61NidNRLIRXOTgU5QE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1571073307; h=Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:Message-ID:References:Sender:Subject:To; bh=T0h/fH73g3XFNkzoVRZTQA+K7quevfijTKc7sC77HcU=; b=Emc/yY8+9rDkHj1tzjGUAz/HqPd090XpdupRq1/SR1cni/KbwdtYiD5BLgtp2Xg4uniqJH8pl5Xommpi48eKMTww1386hICJcljhWNernvg+YEbMXD11X2TloL7Sailn2X1HSagUnhq15GAoW0AZN9M67Unz8zOv42f7G2QNvTQ= ARC-Authentication-Results: i=1; mx.zoho.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 157107330751460.16156394524796; Mon, 14 Oct 2019 10:15:07 -0700 (PDT) Received: from localhost ([::1]:54208 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iK3w1-0001MM-Me for importer@patchew.org; Mon, 14 Oct 2019 13:15:05 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:39883) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iK34G-0006SL-4S for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:36 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iK34B-0007YP-R6 for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:32 -0400 Received: from mail-wm1-x344.google.com ([2a00:1450:4864:20::344]:53425) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1iK34B-0007Xx-FJ for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:27 -0400 Received: by mail-wm1-x344.google.com with SMTP id i16so17902925wmd.3 for ; Mon, 14 Oct 2019 09:19:27 -0700 (PDT) Received: from 8c859074c0ff.ant.amazon.com.com (bzq-79-178-11-117.red.bezeqint.net. [79.178.11.117]) by smtp.gmail.com with ESMTPSA id c132sm28050861wme.27.2019.10.14.09.19.23 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 14 Oct 2019 09:19:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=T0h/fH73g3XFNkzoVRZTQA+K7quevfijTKc7sC77HcU=; b=NW/r3MY88OlRvnOS3x1bUdEs2baONYeOmVEjHmxHI3tQH9l51RZ1OSxla3TMCQxkAi 0Sqc2z3/mnquINa9yYGtkKuCFl4yE97AJ07QncqCcPdx9cLFwsPbqzjqSXWzBQdJvMJb 70iYRM19efvkGyuwDpRugfX/fP8QfU//pxbCHDfNpRUp3IhQqfCvK+NYwcC4D7244AEx 5s0Qu0am4MpVlHZASLU0C1H7DuyNZuF8d0cOhGZ29i/iMfR1paKqUl2VPwR56N+wQyTA eVX6nYtpzIdmLQgP/fKl+RS9eENMLlKiMJr1nZ9FzeI/rFnbn5j1feDS4804/2X8Zv3y kYlA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=T0h/fH73g3XFNkzoVRZTQA+K7quevfijTKc7sC77HcU=; b=DEFQp0P/oKpMRMg0ykOwwlJzgueA4e3uqOtW0jOVJM9nh0lHxRvIHd6qWJ+EL2gnTr o1j7BSgtdCyuQGma8wC/2bPz9nSQuAARO123x7Ft/yvoTtRwuTRFvrlqHXi3LiQSkmmU sKeWAYiKobZlx+7baZpaaqbLqhhnU9XYiPbIGL0lZkRFvUtA0IZxi0v0oA55dn8vwmAm WAUDe1mR03tbChrzIzMR31caSIDBrW0ZSo8rhuG6Lsf2WKguVpBSMKSyxCpn2Zbyk0sC EYm+Y2MOesldtilHy2BeEe3FFGOt51XvOZBFM2iBp3AClC485UYvCx5y5IQFnBVHKPSr D00w== X-Gm-Message-State: APjAAAVTKRO7c3d+QbnU4OWVk7qT+yO1BRnwNM68XkBWDcZCCyOpcufc qRqJJCKGj3ZgX5mw5hSSU7nyLa2Zpdk= X-Google-Smtp-Source: APXvYqxtSLZZBg/9rKi8JBIB4a1+36o3AkgHgd2yct8ushDvpv17lSsOdgK+kbNlFivzHyR4NFGfyA== X-Received: by 2002:a05:600c:2107:: with SMTP id u7mr15625891wml.13.1571069965602; Mon, 14 Oct 2019 09:19:25 -0700 (PDT) From: Michael Rolnik To: qemu-devel@nongnu.org Subject: [PATCH v32 10/13] target/avr: Add limited support for USART and 16 bit timer peripherals Date: Mon, 14 Oct 2019 19:18:40 +0300 Message-Id: <20191014161843.84845-11-mrolnik@gmail.com> X-Mailer: git-send-email 2.17.2 (Apple Git-113) In-Reply-To: <20191014161843.84845-1-mrolnik@gmail.com> References: <20191014161843.84845-1-mrolnik@gmail.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::344 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: thuth@redhat.com, richard.henderson@linaro.org, Sarah Harris , dovgaluk@ispras.ru, imammedo@redhat.com, philmd@redhat.com, aleksandar.m.mail@gmail.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Sarah Harris These were designed to facilitate testing but should provide enough functio= n to be useful in other contexts. Only a subset of the functions of each peripheral is implemented, mainly du= e to the lack of a standard way to handle electrical connections (like GPIO= pins). Signed-off-by: Sarah Harris --- hw/char/Kconfig | 3 + hw/char/Makefile.objs | 1 + hw/char/avr_usart.c | 324 ++++++++++++++++++ hw/misc/Kconfig | 3 + hw/misc/Makefile.objs | 2 + hw/misc/avr_mask.c | 112 ++++++ hw/timer/Kconfig | 3 + hw/timer/Makefile.objs | 1 + hw/timer/avr_timer16.c | 605 +++++++++++++++++++++++++++++++++ include/hw/char/avr_usart.h | 97 ++++++ include/hw/misc/avr_mask.h | 47 +++ include/hw/timer/avr_timer16.h | 97 ++++++ 12 files changed, 1295 insertions(+) create mode 100644 hw/char/avr_usart.c create mode 100644 hw/misc/avr_mask.c create mode 100644 hw/timer/avr_timer16.c create mode 100644 include/hw/char/avr_usart.h create mode 100644 include/hw/misc/avr_mask.h create mode 100644 include/hw/timer/avr_timer16.h diff --git a/hw/char/Kconfig b/hw/char/Kconfig index 40e7a8b8bb..331b20983f 100644 --- a/hw/char/Kconfig +++ b/hw/char/Kconfig @@ -46,3 +46,6 @@ config SCLPCONSOLE =20 config TERMINAL3270 bool + +config AVR_USART + bool diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs index 02d8a66925..09ed50f1d0 100644 --- a/hw/char/Makefile.objs +++ b/hw/char/Makefile.objs @@ -21,6 +21,7 @@ obj-$(CONFIG_PSERIES) +=3D spapr_vty.o obj-$(CONFIG_DIGIC) +=3D digic-uart.o obj-$(CONFIG_STM32F2XX_USART) +=3D stm32f2xx_usart.o obj-$(CONFIG_RASPI) +=3D bcm2835_aux.o +obj-$(CONFIG_AVR_USART) +=3D avr_usart.o =20 common-obj-$(CONFIG_CMSDK_APB_UART) +=3D cmsdk-apb-uart.o common-obj-$(CONFIG_ETRAXFS) +=3D etraxfs_ser.o diff --git a/hw/char/avr_usart.c b/hw/char/avr_usart.c new file mode 100644 index 0000000000..9ca3c2a1cd --- /dev/null +++ b/hw/char/avr_usart.c @@ -0,0 +1,324 @@ +/* + * AVR USART + * + * Copyright (c) 2018 University of Kent + * Author: Sarah Harris + * + * Permission is hereby granted, free of charge, to any person obtaining a= copy + * of this software and associated documentation files (the "Software"), t= o deal + * in the Software without restriction, including without limitation the r= ights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or se= ll + * 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 OT= HER + * 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 "hw/char/avr_usart.h" +#include "qemu/log.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" + +static int avr_usart_can_receive(void *opaque) +{ + AVRUsartState *usart =3D opaque; + + if (usart->data_valid || !(usart->csrb & USART_CSRB_RXEN)) { + return 0; + } + return 1; +} + +static void avr_usart_receive(void *opaque, const uint8_t *buffer, int siz= e) +{ + AVRUsartState *usart =3D opaque; + assert(size =3D=3D 1); + assert(!usart->data_valid); + usart->data =3D buffer[0]; + usart->data_valid =3D true; + usart->csra |=3D USART_CSRA_RXC; + if (usart->csrb & USART_CSRB_RXCIE) { + qemu_set_irq(usart->rxc_irq, 1); + } +} + +static void update_char_mask(AVRUsartState *usart) +{ + uint8_t mode =3D ((usart->csrc & USART_CSRC_CSZ0) ? 1 : 0) | + ((usart->csrc & USART_CSRC_CSZ1) ? 2 : 0) | + ((usart->csrb & USART_CSRB_CSZ2) ? 4 : 0); + switch (mode) { + case 0: + usart->char_mask =3D 0b11111; + break; + case 1: + usart->char_mask =3D 0b111111; + break; + case 2: + usart->char_mask =3D 0b1111111; + break; + case 3: + usart->char_mask =3D 0b11111111; + break; + case 4: + /* Fallthrough. */ + case 5: + /* Fallthrough. */ + case 6: + qemu_log_mask( + LOG_GUEST_ERROR, + "%s: Reserved character size 0x%x\n", + __func__, + mode); + break; + case 7: + qemu_log_mask( + LOG_GUEST_ERROR, + "%s: Nine bit character size not supported (forcing eight)\n", + __func__); + usart->char_mask =3D 0b11111111; + break; + default: + assert(0); + } +} + +static void avr_usart_reset(DeviceState *dev) +{ + AVRUsartState *usart =3D AVR_USART(dev); + usart->data_valid =3D false; + usart->csra =3D 0b00100000; + usart->csrb =3D 0b00000000; + usart->csrc =3D 0b00000110; + usart->brrl =3D 0; + usart->brrh =3D 0; + update_char_mask(usart); + qemu_set_irq(usart->rxc_irq, 0); + qemu_set_irq(usart->txc_irq, 0); + qemu_set_irq(usart->dre_irq, 0); +} + +static uint64_t avr_usart_read(void *opaque, hwaddr addr, unsigned int siz= e) +{ + AVRUsartState *usart =3D opaque; + uint8_t data; + assert(size =3D=3D 1); + + if (!usart->enabled) { + return 0; + } + + switch (addr) { + case USART_DR: + if (!(usart->csrb & USART_CSRB_RXEN)) { + /* Receiver disabled, ignore. */ + return 0; + } + if (usart->data_valid) { + data =3D usart->data & usart->char_mask; + usart->data_valid =3D false; + } else { + data =3D 0; + } + usart->csra &=3D 0xff ^ USART_CSRA_RXC; + qemu_set_irq(usart->rxc_irq, 0); + qemu_chr_fe_accept_input(&usart->chr); + return data; + case USART_CSRA: + return usart->csra; + case USART_CSRB: + return usart->csrb; + case USART_CSRC: + return usart->csrc; + case USART_BRRL: + return usart->brrl; + case USART_BRRH: + return usart->brrh; + default: + qemu_log_mask( + LOG_GUEST_ERROR, + "%s: Bad offset 0x%"HWADDR_PRIx"\n", + __func__, + addr); + } + return 0; +} + +static void avr_usart_write(void *opaque, hwaddr addr, uint64_t value, + unsigned int size) +{ + AVRUsartState *usart =3D opaque; + uint8_t mask; + uint8_t data; + assert((value & 0xff) =3D=3D value); + assert(size =3D=3D 1); + + if (!usart->enabled) { + return; + } + + switch (addr) { + case USART_DR: + if (!(usart->csrb & USART_CSRB_TXEN)) { + /* Transmitter disabled, ignore. */ + return; + } + usart->csra |=3D USART_CSRA_TXC; + usart->csra |=3D USART_CSRA_DRE; + if (usart->csrb & USART_CSRB_TXCIE) { + qemu_set_irq(usart->txc_irq, 1); + usart->csra &=3D 0xff ^ USART_CSRA_TXC; + } + if (usart->csrb & USART_CSRB_DREIE) { + qemu_set_irq(usart->dre_irq, 1); + } + data =3D value; + qemu_chr_fe_write_all(&usart->chr, &data, 1); + break; + case USART_CSRA: + mask =3D 0b01000011; + /* Mask read-only bits. */ + value =3D (value & mask) | (usart->csra & (0xff ^ mask)); + usart->csra =3D value; + if (value & USART_CSRA_TXC) { + usart->csra ^=3D USART_CSRA_TXC; + qemu_set_irq(usart->txc_irq, 0); + } + if (value & USART_CSRA_MPCM) { + qemu_log_mask( + LOG_GUEST_ERROR, + "%s: MPCM not supported by USART\n", + __func__); + } + break; + case USART_CSRB: + mask =3D 0b11111101; + /* Mask read-only bits. */ + value =3D (value & mask) | (usart->csrb & (0xff ^ mask)); + usart->csrb =3D value; + if (!(value & USART_CSRB_RXEN)) { + /* Receiver disabled, flush input buffer. */ + usart->data_valid =3D false; + } + qemu_set_irq(usart->rxc_irq, + ((value & USART_CSRB_RXCIE) && + (usart->csra & USART_CSRA_RXC)) ? 1 : 0); + qemu_set_irq(usart->txc_irq, + ((value & USART_CSRB_TXCIE) && + (usart->csra & USART_CSRA_TXC)) ? 1 : 0); + qemu_set_irq(usart->dre_irq, + ((value & USART_CSRB_DREIE) && + (usart->csra & USART_CSRA_DRE)) ? 1 : 0); + update_char_mask(usart); + break; + case USART_CSRC: + usart->csrc =3D value; + if ((value & USART_CSRC_MSEL1) && (value & USART_CSRC_MSEL0)) { + qemu_log_mask( + LOG_GUEST_ERROR, + "%s: SPI mode not supported by USART\n", + __func__); + } + if ((value & USART_CSRC_MSEL1) && !(value & USART_CSRC_MSEL0)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad USART mode\n", __func_= _); + } + if (!(value & USART_CSRC_PM1) && (value & USART_CSRC_PM0)) { + qemu_log_mask( + LOG_GUEST_ERROR, + "%s: Bad USART parity mode\n", + __func__); + } + update_char_mask(usart); + break; + case USART_BRRL: + usart->brrl =3D value; + break; + case USART_BRRH: + usart->brrh =3D value & 0b00001111; + break; + default: + qemu_log_mask( + LOG_GUEST_ERROR, + "%s: Bad offset 0x%"HWADDR_PRIx"\n", + __func__, + addr); + } +} + +static const MemoryRegionOps avr_usart_ops =3D { + .read =3D avr_usart_read, + .write =3D avr_usart_write, + .endianness =3D DEVICE_NATIVE_ENDIAN, + .impl =3D {.min_access_size =3D 1, .max_access_size =3D 1} +}; + +static Property avr_usart_properties[] =3D { + DEFINE_PROP_CHR("chardev", AVRUsartState, chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static void avr_usart_pr(void *opaque, int irq, int level) +{ + AVRUsartState *s =3D AVR_USART(opaque); + + s->enabled =3D !level; + + if (!s->enabled) { + avr_usart_reset(DEVICE(s)); + } +} + +static void avr_usart_init(Object *obj) +{ + AVRUsartState *s =3D AVR_USART(obj); + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rxc_irq); + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->dre_irq); + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->txc_irq); + memory_region_init_io(&s->mmio, obj, &avr_usart_ops, s, TYPE_AVR_USART= , 8); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); + qdev_init_gpio_in(DEVICE(s), avr_usart_pr, 1); + s->enabled =3D true; +} + +static void avr_usart_realize(DeviceState *dev, Error **errp) +{ + AVRUsartState *s =3D AVR_USART(dev); + qemu_chr_fe_set_handlers(&s->chr, avr_usart_can_receive, + avr_usart_receive, NULL, NULL, + s, NULL, true); + avr_usart_reset(dev); +} + +static void avr_usart_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + + dc->reset =3D avr_usart_reset; + dc->props =3D avr_usart_properties; + dc->realize =3D avr_usart_realize; +} + +static const TypeInfo avr_usart_info =3D { + .name =3D TYPE_AVR_USART, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(AVRUsartState), + .instance_init =3D avr_usart_init, + .class_init =3D avr_usart_class_init, +}; + +static void avr_usart_register_types(void) +{ + type_register_static(&avr_usart_info); +} + +type_init(avr_usart_register_types) diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index 51754bb47c..eb9e3210f4 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -120,4 +120,7 @@ config AUX config UNIMP bool =20 +config AVR_MASK + bool + source macio/Kconfig diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index a150680966..946bfc396d 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -80,3 +80,5 @@ common-obj-$(CONFIG_MSF2) +=3D msf2-sysreg.o common-obj-$(CONFIG_NRF51_SOC) +=3D nrf51_rng.o =20 common-obj-$(CONFIG_GRLIB) +=3D grlib_ahb_apb_pnp.o + +obj-$(CONFIG_AVR_MASK) +=3D avr_mask.o diff --git a/hw/misc/avr_mask.c b/hw/misc/avr_mask.c new file mode 100644 index 0000000000..3af82ed9c1 --- /dev/null +++ b/hw/misc/avr_mask.c @@ -0,0 +1,112 @@ +/* + * AVR Power Reduction + * + * Copyright (c) 2019 Michael Rolnik + * + * Permission is hereby granted, free of charge, to any person obtaining a= copy + * of this software and associated documentation files (the "Software"), t= o deal + * in the Software without restriction, including without limitation the r= ights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or se= ll + * 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 OT= HER + * 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 "hw/misc/avr_mask.h" +#include "qemu/log.h" +#include "hw/qdev-properties.h" +#include "hw/irq.h" + +#define DB_PRINT(fmt, args...) /* Nothing */ +/*#define DB_PRINT(fmt, args...) printf("%s: " fmt "\n", __func__, ## args= )*/ + +static void avr_mask_reset(DeviceState *dev) +{ + AVRMaskState *s =3D AVR_MASK(dev); + + s->val =3D 0x00; + + for (int i =3D 0; i < 8; i++) { + qemu_set_irq(s->irq[i], 0); + } +} + +static uint64_t avr_mask_read(void *opaque, hwaddr offset, unsigned size) +{ + assert(size =3D=3D 1); + assert(offset =3D=3D 0); + AVRMaskState *s =3D opaque; + + return (uint64_t)s->val; +} + +static void avr_mask_write(void *opaque, hwaddr offset, + uint64_t val64, unsigned size) +{ + assert(size =3D=3D 1); + assert(offset =3D=3D 0); + AVRMaskState *s =3D opaque; + uint8_t val8 =3D val64; + + DB_PRINT("write %d to offset %d", val8, (uint8_t)offset); + + s->val =3D val8; + for (int i =3D 0; i < 8; i++) { + qemu_set_irq(s->irq[i], (val8 & (1 << i)) !=3D 0); + } +} + +static const MemoryRegionOps avr_mask_ops =3D { + .read =3D avr_mask_read, + .write =3D avr_mask_write, + .endianness =3D DEVICE_NATIVE_ENDIAN, + .impl =3D {.max_access_size =3D 1} +}; + +static void avr_mask_init(Object *dev) +{ + AVRMaskState *s =3D AVR_MASK(dev); + SysBusDevice *busdev =3D SYS_BUS_DEVICE(dev); + + memory_region_init_io(&s->iomem, dev, &avr_mask_ops, s, TYPE_AVR_MASK, + 0x01); + sysbus_init_mmio(busdev, &s->iomem); + + for (int i =3D 0; i < 8; i++) { + sysbus_init_irq(busdev, &s->irq[i]); + } + s->val =3D 0x00; +} + +static void avr_mask_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + + dc->reset =3D avr_mask_reset; +} + +static const TypeInfo avr_mask_info =3D { + .name =3D TYPE_AVR_MASK, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(AVRMaskState), + .class_init =3D avr_mask_class_init, + .instance_init =3D avr_mask_init, +}; + +static void avr_mask_register_types(void) +{ + type_register_static(&avr_mask_info); +} + +type_init(avr_mask_register_types) diff --git a/hw/timer/Kconfig b/hw/timer/Kconfig index eefc95f35e..3bea322184 100644 --- a/hw/timer/Kconfig +++ b/hw/timer/Kconfig @@ -58,3 +58,6 @@ config CMSDK_APB_TIMER config CMSDK_APB_DUALTIMER bool select PTIMER + +config AVR_TIMER16 + bool diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs index 123d92c969..4f853e265d 100644 --- a/hw/timer/Makefile.objs +++ b/hw/timer/Makefile.objs @@ -35,6 +35,7 @@ obj-$(CONFIG_PXA2XX) +=3D pxa2xx_timer.o obj-$(CONFIG_SH4) +=3D sh_timer.o obj-$(CONFIG_DIGIC) +=3D digic-timer.o obj-$(CONFIG_MIPS_CPS) +=3D mips_gictimer.o +obj-$(CONFIG_AVR_TIMER16) +=3D avr_timer16.o =20 obj-$(CONFIG_MC146818RTC) +=3D mc146818rtc.o =20 diff --git a/hw/timer/avr_timer16.c b/hw/timer/avr_timer16.c new file mode 100644 index 0000000000..ac6ef73e77 --- /dev/null +++ b/hw/timer/avr_timer16.c @@ -0,0 +1,605 @@ +/* + * AVR 16 bit timer + * + * Copyright (c) 2018 University of Kent + * Author: Ed Robbins + * + * Permission is hereby granted, free of charge, to any person obtaining a= copy + * of this software and associated documentation files (the "Software"), t= o deal + * in the Software without restriction, including without limitation the r= ights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or se= ll + * 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 OT= HER + * 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. + */ + +/* + * Driver for 16 bit timers on 8 bit AVR devices. + * Note: + * ATmega640/V-1280/V-1281/V-2560/V-2561/V timers 1, 3, 4 and 5 are 16 bit + */ + +/* + * XXX TODO: Power Reduction Register support + * prescaler pause support + * PWM modes, GPIO, output capture pins, input compare pin + */ + +#include "qemu/osdep.h" +#include "hw/timer/avr_timer16.h" +#include "qemu/log.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" + +/* Register offsets */ +#define T16_CRA 0x0 +#define T16_CRB 0x1 +#define T16_CRC 0x2 +#define T16_CNTL 0x4 +#define T16_CNTH 0x5 +#define T16_ICRL 0x6 +#define T16_ICRH 0x7 +#define T16_OCRAL 0x8 +#define T16_OCRAH 0x9 +#define T16_OCRBL 0xa +#define T16_OCRBH 0xb +#define T16_OCRCL 0xc +#define T16_OCRCH 0xd + +/* Field masks */ +#define T16_CRA_WGM01 0x3 +#define T16_CRA_COMC 0xc +#define T16_CRA_COMB 0x30 +#define T16_CRA_COMA 0xc0 +#define T16_CRA_OC_CONF \ + (T16_CRA_COMA | T16_CRA_COMB | T16_CRA_COMC) + +#define T16_CRB_CS 0x7 +#define T16_CRB_WGM23 0x18 +#define T16_CRB_ICES 0x40 +#define T16_CRB_ICNC 0x80 + +#define T16_CRC_FOCC 0x20 +#define T16_CRC_FOCB 0x40 +#define T16_CRC_FOCA 0x80 + +/* Fields masks both TIMSK and TIFR (interrupt mask/flag registers) */ +#define T16_INT_TOV 0x1 /* Timer overflow */ +#define T16_INT_OCA 0x2 /* Output compare A */ +#define T16_INT_OCB 0x4 /* Output compare B */ +#define T16_INT_OCC 0x8 /* Output compare C */ +#define T16_INT_IC 0x20 /* Input capture */ + +/* Clock source values */ +#define T16_CLKSRC_STOPPED 0 +#define T16_CLKSRC_DIV1 1 +#define T16_CLKSRC_DIV8 2 +#define T16_CLKSRC_DIV64 3 +#define T16_CLKSRC_DIV256 4 +#define T16_CLKSRC_DIV1024 5 +#define T16_CLKSRC_EXT_FALLING 6 +#define T16_CLKSRC_EXT_RISING 7 + +/* Timer mode values (not including PWM modes) */ +#define T16_MODE_NORMAL 0 +#define T16_MODE_CTC_OCRA 4 +#define T16_MODE_CTC_ICR 12 + +/* Accessors */ +#define CLKSRC(t16) (t16->crb & T16_CRB_CS) +#define MODE(t16) (((t16->crb & T16_CRB_WGM23) >> 1) | \ + (t16->cra & T16_CRA_WGM01)) +#define CNT(t16) VAL16(t16->cntl, t16->cnth) +#define OCRA(t16) VAL16(t16->ocral, t16->ocrah) +#define OCRB(t16) VAL16(t16->ocrbl, t16->ocrbh) +#define OCRC(t16) VAL16(t16->ocrcl, t16->ocrch) +#define ICR(t16) VAL16(t16->icrl, t16->icrh) + +/* Helper macros */ +#define VAL16(l, h) ((h << 8) | l) +#define ERROR(fmt, args...) \ + qemu_log_mask(LOG_GUEST_ERROR, "%s: " fmt "\n", __func__, ## args) +#define DB_PRINT(fmt, args...) /* Nothing */ +/*#define DB_PRINT(fmt, args...) printf("%s: " fmt "\n", __func__, ## args= )*/ + +static inline int64_t avr_timer16_ns_to_ticks(AVRTimer16State *t16, int64_= t t) +{ + if (t16->period_ns =3D=3D 0) { + return 0; + } + return t / t16->period_ns; +} + +static void avr_timer16_update_cnt(AVRTimer16State *t16) +{ + uint16_t cnt; + cnt =3D avr_timer16_ns_to_ticks(t16, qemu_clock_get_ns(QEMU_CLOCK_VIRT= UAL) - + t16->reset_time_ns); + t16->cntl =3D (uint8_t)(cnt & 0xff); + t16->cnth =3D (uint8_t)((cnt & 0xff00) >> 8); +} + +static inline void avr_timer16_recalc_reset_time(AVRTimer16State *t16) +{ + t16->reset_time_ns =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - + CNT(t16) * t16->period_ns; +} + +static void avr_timer16_clock_reset(AVRTimer16State *t16) +{ + t16->cntl =3D 0; + t16->cnth =3D 0; + t16->reset_time_ns =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); +} + +static void avr_timer16_clksrc_update(AVRTimer16State *t16) +{ + uint16_t divider =3D 0; + switch (CLKSRC(t16)) { + case T16_CLKSRC_EXT_FALLING: + case T16_CLKSRC_EXT_RISING: + ERROR("external clock source unsupported"); + goto end; + case T16_CLKSRC_STOPPED: + goto end; + case T16_CLKSRC_DIV1: + divider =3D 1; + break; + case T16_CLKSRC_DIV8: + divider =3D 8; + break; + case T16_CLKSRC_DIV64: + divider =3D 64; + break; + case T16_CLKSRC_DIV256: + divider =3D 256; + break; + case T16_CLKSRC_DIV1024: + divider =3D 1024; + break; + default: + goto end; + } + t16->freq_hz =3D t16->cpu_freq_hz / divider; + t16->period_ns =3D 1000000000ULL / t16->freq_hz; + DB_PRINT("Timer frequency %" PRIu64 " hz, period %" PRIu64 " ns (%f s)= ", + t16->freq_hz, t16->period_ns, 1 / (double)t16->freq_hz); +end: + return; +} + +static void avr_timer16_set_alarm(AVRTimer16State *t16) +{ + if (CLKSRC(t16) =3D=3D T16_CLKSRC_EXT_FALLING || + CLKSRC(t16) =3D=3D T16_CLKSRC_EXT_RISING || + CLKSRC(t16) =3D=3D T16_CLKSRC_STOPPED) { + /* Timer is disabled or set to external clock source (unsupported)= */ + goto end; + } + + uint64_t alarm_offset =3D 0xffff; + enum NextInterrupt next_interrupt =3D OVERFLOW; + + switch (MODE(t16)) { + case T16_MODE_NORMAL: + /* Normal mode */ + if (OCRA(t16) < alarm_offset && OCRA(t16) > CNT(t16) && + (t16->imsk & T16_INT_OCA)) { + alarm_offset =3D OCRA(t16); + next_interrupt =3D COMPA; + } + break; + case T16_MODE_CTC_OCRA: + /* CTC mode, top =3D ocra */ + if (OCRA(t16) < alarm_offset && OCRA(t16) > CNT(t16)) { + alarm_offset =3D OCRA(t16); + next_interrupt =3D COMPA; + } + break; + case T16_MODE_CTC_ICR: + /* CTC mode, top =3D icr */ + if (ICR(t16) < alarm_offset && ICR(t16) > CNT(t16)) { + alarm_offset =3D ICR(t16); + next_interrupt =3D CAPT; + } + if (OCRA(t16) < alarm_offset && OCRA(t16) > CNT(t16) && + (t16->imsk & T16_INT_OCA)) { + alarm_offset =3D OCRA(t16); + next_interrupt =3D COMPA; + } + break; + default: + ERROR("pwm modes are unsupported"); + goto end; + } + if (OCRB(t16) < alarm_offset && OCRB(t16) > CNT(t16) && + (t16->imsk & T16_INT_OCB)) { + alarm_offset =3D OCRB(t16); + next_interrupt =3D COMPB; + } + if (OCRC(t16) < alarm_offset && OCRB(t16) > CNT(t16) && + (t16->imsk & T16_INT_OCC)) { + alarm_offset =3D OCRB(t16); + next_interrupt =3D COMPC; + } + alarm_offset -=3D CNT(t16); + + t16->next_interrupt =3D next_interrupt; + uint64_t alarm_ns =3D + t16->reset_time_ns + ((CNT(t16) + alarm_offset) * t16->period_ns); + timer_mod(t16->timer, alarm_ns); + + DB_PRINT("next alarm %" PRIu64 " ns from now", + alarm_offset * t16->period_ns); + +end: + return; +} + +static void avr_timer16_interrupt(void *opaque) +{ + AVRTimer16State *t16 =3D opaque; + uint8_t mode =3D MODE(t16); + + avr_timer16_update_cnt(t16); + + if (CLKSRC(t16) =3D=3D T16_CLKSRC_EXT_FALLING || + CLKSRC(t16) =3D=3D T16_CLKSRC_EXT_RISING || + CLKSRC(t16) =3D=3D T16_CLKSRC_STOPPED) { + /* Timer is disabled or set to external clock source (unsupported)= */ + return; + } + + DB_PRINT("interrupt, cnt =3D %d", CNT(t16)); + + /* Counter overflow */ + if (t16->next_interrupt =3D=3D OVERFLOW) { + DB_PRINT("0xffff overflow"); + avr_timer16_clock_reset(t16); + if (t16->imsk & T16_INT_TOV) { + t16->ifr |=3D T16_INT_TOV; + qemu_set_irq(t16->ovf_irq, 1); + } + } + /* Check for ocra overflow in CTC mode */ + if (mode =3D=3D T16_MODE_CTC_OCRA && t16->next_interrupt =3D=3D COMPA)= { + DB_PRINT("CTC OCRA overflow"); + avr_timer16_clock_reset(t16); + } + /* Check for icr overflow in CTC mode */ + if (mode =3D=3D T16_MODE_CTC_ICR && t16->next_interrupt =3D=3D CAPT) { + DB_PRINT("CTC ICR overflow"); + avr_timer16_clock_reset(t16); + if (t16->imsk & T16_INT_IC) { + t16->ifr |=3D T16_INT_IC; + qemu_set_irq(t16->capt_irq, 1); + } + } + /* Check for output compare interrupts */ + if (t16->imsk & T16_INT_OCA && t16->next_interrupt =3D=3D COMPA) { + t16->ifr |=3D T16_INT_OCA; + qemu_set_irq(t16->compa_irq, 1); + } + if (t16->imsk & T16_INT_OCB && t16->next_interrupt =3D=3D COMPB) { + t16->ifr |=3D T16_INT_OCB; + qemu_set_irq(t16->compb_irq, 1); + } + if (t16->imsk & T16_INT_OCC && t16->next_interrupt =3D=3D COMPC) { + t16->ifr |=3D T16_INT_OCC; + qemu_set_irq(t16->compc_irq, 1); + } + avr_timer16_set_alarm(t16); +} + +static void avr_timer16_reset(DeviceState *dev) +{ + AVRTimer16State *t16 =3D AVR_TIMER16(dev); + + avr_timer16_clock_reset(t16); + avr_timer16_clksrc_update(t16); + avr_timer16_set_alarm(t16); + + qemu_set_irq(t16->capt_irq, 0); + qemu_set_irq(t16->compa_irq, 0); + qemu_set_irq(t16->compb_irq, 0); + qemu_set_irq(t16->compc_irq, 0); + qemu_set_irq(t16->ovf_irq, 0); +} + +static uint64_t avr_timer16_read(void *opaque, hwaddr offset, unsigned siz= e) +{ + assert(size =3D=3D 1); + AVRTimer16State *t16 =3D opaque; + uint8_t retval =3D 0; + + switch (offset) { + case T16_CRA: + retval =3D t16->cra; + break; + case T16_CRB: + retval =3D t16->crb; + break; + case T16_CRC: + retval =3D t16->crc; + break; + case T16_CNTL: + avr_timer16_update_cnt(t16); + t16->rtmp =3D t16->cnth; + retval =3D t16->cntl; + break; + case T16_CNTH: + retval =3D t16->rtmp; + break; + case T16_ICRL: + /* + * The timer copies cnt to icr when the input capture pin changes + * state or when the analog comparator has a match. We don't + * emulate this behaviour. We do support it's use for defining a + * TOP value in T16_MODE_CTC_ICR + */ + t16->rtmp =3D t16->icrh; + retval =3D t16->icrl; + break; + case T16_ICRH: + retval =3D t16->rtmp; + break; + case T16_OCRAL: + retval =3D t16->ocral; + break; + case T16_OCRAH: + retval =3D t16->ocrah; + break; + case T16_OCRBL: + retval =3D t16->ocrbl; + break; + case T16_OCRBH: + retval =3D t16->ocrbh; + break; + case T16_OCRCL: + retval =3D t16->ocrcl; + break; + case T16_OCRCH: + retval =3D t16->ocrch; + break; + default: + break; + } + return (uint64_t)retval; +} + +static void avr_timer16_write(void *opaque, hwaddr offset, + uint64_t val64, unsigned size) +{ + assert(size =3D=3D 1); + AVRTimer16State *t16 =3D opaque; + uint8_t val8 =3D (uint8_t)val64; + uint8_t prev_clk_src =3D CLKSRC(t16); + + DB_PRINT("write %d to offset %d", val8, (uint8_t)offset); + + switch (offset) { + case T16_CRA: + t16->cra =3D val8; + if (t16->cra & T16_CRA_OC_CONF) { + ERROR("output compare pins unsupported"); + } + break; + case T16_CRB: + t16->crb =3D val8; + if (t16->crb & T16_CRB_ICNC) { + ERROR("input capture noise canceller unsupported"); + } + if (t16->crb & T16_CRB_ICES) { + ERROR("input capture unsupported"); + } + if (CLKSRC(t16) !=3D prev_clk_src) { + avr_timer16_clksrc_update(t16); + if (prev_clk_src =3D=3D T16_CLKSRC_STOPPED) { + t16->reset_time_ns =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUA= L); + } + } + break; + case T16_CRC: + t16->crc =3D val8; + ERROR("output compare pins unsupported"); + break; + case T16_CNTL: + /* + * CNT is the 16-bit counter value, it must be read/written via + * a temporary register (rtmp) to make the read/write atomic. + */ + /* ICR also has this behaviour, and shares rtmp */ + /* + * Writing CNT blocks compare matches for one clock cycle. + * Writing CNT to TOP or to an OCR value (if in use) will + * skip the relevant interrupt + */ + t16->cntl =3D val8; + t16->cnth =3D t16->rtmp; + avr_timer16_recalc_reset_time(t16); + break; + case T16_CNTH: + t16->rtmp =3D val8; + break; + case T16_ICRL: + /* ICR can only be written in mode T16_MODE_CTC_ICR */ + if (MODE(t16) =3D=3D T16_MODE_CTC_ICR) { + t16->icrl =3D val8; + t16->icrh =3D t16->rtmp; + } + break; + case T16_ICRH: + if (MODE(t16) =3D=3D T16_MODE_CTC_ICR) { + t16->rtmp =3D val8; + } + break; + case T16_OCRAL: + /* + * OCRn cause the relevant output compare flag to be raised, and + * trigger an interrupt, when CNT is equal to the value here + */ + t16->ocral =3D val8; + break; + case T16_OCRAH: + t16->ocrah =3D val8; + break; + case T16_OCRBL: + t16->ocrbl =3D val8; + break; + case T16_OCRBH: + t16->ocrbh =3D val8; + break; + case T16_OCRCL: + t16->ocrcl =3D val8; + break; + case T16_OCRCH: + t16->ocrch =3D val8; + break; + default: + break; + } + avr_timer16_set_alarm(t16); +} + +static uint64_t avr_timer16_imsk_read(void *opaque, + hwaddr offset, + unsigned size) +{ + assert(size =3D=3D 1); + AVRTimer16State *t16 =3D opaque; + if (offset !=3D 0) { + return 0; + } + return t16->imsk; +} + +static void avr_timer16_imsk_write(void *opaque, hwaddr offset, + uint64_t val64, unsigned size) +{ + assert(size =3D=3D 1); + AVRTimer16State *t16 =3D opaque; + if (offset !=3D 0) { + return; + } + t16->imsk =3D (uint8_t)val64; +} + +static uint64_t avr_timer16_ifr_read(void *opaque, + hwaddr offset, + unsigned size) +{ + assert(size =3D=3D 1); + AVRTimer16State *t16 =3D opaque; + if (offset !=3D 0) { + return 0; + } + return t16->ifr; +} + +static void avr_timer16_ifr_write(void *opaque, hwaddr offset, + uint64_t val64, unsigned size) +{ + assert(size =3D=3D 1); + AVRTimer16State *t16 =3D opaque; + if (offset !=3D 0) { + return; + } + t16->ifr =3D (uint8_t)val64; +} + +static const MemoryRegionOps avr_timer16_ops =3D { + .read =3D avr_timer16_read, + .write =3D avr_timer16_write, + .endianness =3D DEVICE_NATIVE_ENDIAN, + .impl =3D {.max_access_size =3D 1} +}; + +static const MemoryRegionOps avr_timer16_imsk_ops =3D { + .read =3D avr_timer16_imsk_read, + .write =3D avr_timer16_imsk_write, + .endianness =3D DEVICE_NATIVE_ENDIAN, + .impl =3D {.max_access_size =3D 1} +}; + +static const MemoryRegionOps avr_timer16_ifr_ops =3D { + .read =3D avr_timer16_ifr_read, + .write =3D avr_timer16_ifr_write, + .endianness =3D DEVICE_NATIVE_ENDIAN, + .impl =3D {.max_access_size =3D 1} +}; + +static Property avr_timer16_properties[] =3D { + DEFINE_PROP_UINT64("cpu-frequency-hz", struct AVRTimer16State, + cpu_freq_hz, 20000000), + DEFINE_PROP_END_OF_LIST(), +}; + +static void avr_timer16_pr(void *opaque, int irq, int level) +{ + AVRTimer16State *s =3D AVR_TIMER16(opaque); + + s->enabled =3D !level; + + if (!s->enabled) { + avr_timer16_reset(DEVICE(s)); + } +} + +static void avr_timer16_init(Object *obj) +{ + AVRTimer16State *s =3D AVR_TIMER16(obj); + + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->capt_irq); + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->compa_irq); + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->compb_irq); + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->compc_irq); + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->ovf_irq); + + memory_region_init_io(&s->iomem, obj, &avr_timer16_ops, + s, TYPE_AVR_TIMER16, 0xe); + memory_region_init_io(&s->imsk_iomem, obj, &avr_timer16_imsk_ops, + s, TYPE_AVR_TIMER16, 0x1); + memory_region_init_io(&s->ifr_iomem, obj, &avr_timer16_ifr_ops, + s, TYPE_AVR_TIMER16, 0x1); + + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->imsk_iomem); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->ifr_iomem); + qdev_init_gpio_in(DEVICE(s), avr_timer16_pr, 1); + + s->timer =3D timer_new_ns(QEMU_CLOCK_VIRTUAL, avr_timer16_interrupt, s= ); + s->enabled =3D true; +} + +static void avr_timer16_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + + dc->reset =3D avr_timer16_reset; + dc->props =3D avr_timer16_properties; +} + +static const TypeInfo avr_timer16_info =3D { + .name =3D TYPE_AVR_TIMER16, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(AVRTimer16State), + .instance_init =3D avr_timer16_init, + .class_init =3D avr_timer16_class_init, +}; + +static void avr_timer16_register_types(void) +{ + type_register_static(&avr_timer16_info); +} + +type_init(avr_timer16_register_types) diff --git a/include/hw/char/avr_usart.h b/include/hw/char/avr_usart.h new file mode 100644 index 0000000000..8e9ee88bbd --- /dev/null +++ b/include/hw/char/avr_usart.h @@ -0,0 +1,97 @@ +/* + * AVR USART + * + * Copyright (c) 2018 University of Kent + * Author: Sarah Harris + * + * Permission is hereby granted, free of charge, to any person obtaining a= copy + * of this software and associated documentation files (the "Software"), t= o deal + * in the Software without restriction, including without limitation the r= ights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or se= ll + * 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 OT= HER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING= FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS = IN + * THE SOFTWARE. + */ + +#ifndef HW_AVR_USART_H +#define HW_AVR_USART_H + +#include "hw/sysbus.h" +#include "chardev/char-fe.h" +#include "hw/hw.h" + +/* Offsets of registers. */ +#define USART_DR 0x06 +#define USART_CSRA 0x00 +#define USART_CSRB 0x01 +#define USART_CSRC 0x02 +#define USART_BRRH 0x05 +#define USART_BRRL 0x04 + +/* Relevant bits in regiters. */ +#define USART_CSRA_RXC (1 << 7) +#define USART_CSRA_TXC (1 << 6) +#define USART_CSRA_DRE (1 << 5) +#define USART_CSRA_MPCM (1 << 0) + +#define USART_CSRB_RXCIE (1 << 7) +#define USART_CSRB_TXCIE (1 << 6) +#define USART_CSRB_DREIE (1 << 5) +#define USART_CSRB_RXEN (1 << 4) +#define USART_CSRB_TXEN (1 << 3) +#define USART_CSRB_CSZ2 (1 << 2) +#define USART_CSRB_RXB8 (1 << 1) +#define USART_CSRB_TXB8 (1 << 0) + +#define USART_CSRC_MSEL1 (1 << 7) +#define USART_CSRC_MSEL0 (1 << 6) +#define USART_CSRC_PM1 (1 << 5) +#define USART_CSRC_PM0 (1 << 4) +#define USART_CSRC_CSZ1 (1 << 2) +#define USART_CSRC_CSZ0 (1 << 1) + +#define TYPE_AVR_USART "avr-usart" +#define AVR_USART(obj) \ + OBJECT_CHECK(AVRUsartState, (obj), TYPE_AVR_USART) + +typedef struct { + /* */ + SysBusDevice parent_obj; + + /* */ + MemoryRegion mmio; + + CharBackend chr; + + bool enabled; + + uint8_t data; + bool data_valid; + uint8_t char_mask; + /* Control and Status Registers */ + uint8_t csra; + uint8_t csrb; + uint8_t csrc; + /* Baud Rate Registers (low/high byte) */ + uint8_t brrh; + uint8_t brrl; + + /* Receive Complete */ + qemu_irq rxc_irq; + /* Transmit Complete */ + qemu_irq txc_irq; + /* Data Register Empty */ + qemu_irq dre_irq; +} AVRUsartState; + +#endif /* HW_AVR_USART_H */ diff --git a/include/hw/misc/avr_mask.h b/include/hw/misc/avr_mask.h new file mode 100644 index 0000000000..d3e21972d8 --- /dev/null +++ b/include/hw/misc/avr_mask.h @@ -0,0 +1,47 @@ +/* + * AVR Power Reduction + * + * Copyright (c) 2019 Michael Rolnik + * + * Permission is hereby granted, free of charge, to any person obtaining a= copy + * of this software and associated documentation files (the "Software"), t= o deal + * in the Software without restriction, including without limitation the r= ights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or se= ll + * 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 OT= HER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING= FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS = IN + * THE SOFTWARE. + */ + +#ifndef HW_avr_mask_H +#define HW_avr_mask_H + +#include "hw/sysbus.h" +#include "chardev/char-fe.h" +#include "hw/hw.h" + + +#define TYPE_AVR_MASK "avr-mask" +#define AVR_MASK(obj) OBJECT_CHECK(AVRMaskState, (obj), TYPE_AVR_MASK) + +typedef struct { + /* */ + SysBusDevice parent_obj; + + /* */ + MemoryRegion iomem; + + uint8_t val; + qemu_irq irq[8]; +} AVRMaskState; + +#endif /* HW_avr_mask_H */ diff --git a/include/hw/timer/avr_timer16.h b/include/hw/timer/avr_timer16.h new file mode 100644 index 0000000000..5639074ce5 --- /dev/null +++ b/include/hw/timer/avr_timer16.h @@ -0,0 +1,97 @@ +/* + * AVR 16 bit timer + * + * Copyright (c) 2018 University of Kent + * Author: Ed Robbins + * + * Permission is hereby granted, free of charge, to any person obtaining a= copy + * of this software and associated documentation files (the "Software"), t= o deal + * in the Software without restriction, including without limitation the r= ights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or se= ll + * 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 OT= HER + * 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. + */ + +/* + * Driver for 16 bit timers on 8 bit AVR devices. + * Note: + * On ATmega640/V-1280/V-1281/V-2560/V-2561/V timers 1, 3, 4 and 5 are 16 = bit + */ + +#ifndef AVR_TIMER16_H +#define AVR_TIMER16_H + +#include "hw/sysbus.h" +#include "qemu/timer.h" +#include "hw/hw.h" + +enum NextInterrupt { + OVERFLOW, + COMPA, + COMPB, + COMPC, + CAPT +}; + +#define TYPE_AVR_TIMER16 "avr-timer16" +#define AVR_TIMER16(obj) \ + OBJECT_CHECK(AVRTimer16State, (obj), TYPE_AVR_TIMER16) + +typedef struct AVRTimer16State { + /* */ + SysBusDevice parent_obj; + + /* */ + MemoryRegion iomem; + MemoryRegion imsk_iomem; + MemoryRegion ifr_iomem; + QEMUTimer *timer; + qemu_irq capt_irq; + qemu_irq compa_irq; + qemu_irq compb_irq; + qemu_irq compc_irq; + qemu_irq ovf_irq; + + bool enabled; + + /* registers */ + uint8_t cra; + uint8_t crb; + uint8_t crc; + uint8_t cntl; + uint8_t cnth; + uint8_t icrl; + uint8_t icrh; + uint8_t ocral; + uint8_t ocrah; + uint8_t ocrbl; + uint8_t ocrbh; + uint8_t ocrcl; + uint8_t ocrch; + /* + * Reads and writes to CNT and ICR utilise a bizarre temporary + * register, which we emulate + */ + uint8_t rtmp; + uint8_t imsk; + uint8_t ifr; + + uint64_t cpu_freq_hz; + uint64_t freq_hz; + uint64_t period_ns; + uint64_t reset_time_ns; + enum NextInterrupt next_interrupt; +} AVRTimer16State; + +#endif /* AVR_TIMER16_H */ --=20 2.17.2 (Apple Git-113) From nobody Tue May 7 17:09:40 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1571075095; cv=none; d=zoho.com; s=zohoarc; b=kKalBVJamtA0h8t2/aQ8L5YsQgBIIruTxaTukL9nvGHww5L3y0bjSRAgtfM6decAdcp8d1ouDchT7J3Skk+1RkzTWSRa5MvJsSCHQpLcZrbKrK9WGPE4ryBcdCCBOleymGxyhyQ86HkeKelNi1q68dB0/ABzJlk6uZAtBQLxMqw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1571075095; h=Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:Message-ID:References:Sender:Subject:To; bh=KnzwXm9DGa8updfHvfNXSEz/qG/OHlkhJSqLyJjiNdY=; b=Idtu0gYqnlBuTkLXXxaA1PAEDWXPsvwjebDqCEc7/lScRb1jY/z1Q1Ej+Z4IULRoYd9kAW6eayt0TSqdJWXMif8ZoWFJdVOXUgmu88VkzGlqXURLDoVrji7NyG6zS/P1rY2k8vsiJhb+gbkseqDjOV0ZcE+YDZdf/C+oo9eih7w= ARC-Authentication-Results: i=1; mx.zoho.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1571075095777178.8301610082118; Mon, 14 Oct 2019 10:44:55 -0700 (PDT) Received: from localhost ([::1]:54850 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iK4Os-0005Dn-MZ for importer@patchew.org; Mon, 14 Oct 2019 13:44:54 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:39889) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iK34H-0006Tc-3z for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:35 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iK34F-0007Zc-0N for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:32 -0400 Received: from mail-wr1-x443.google.com ([2a00:1450:4864:20::443]:35304) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1iK34E-0007ZO-PT for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:30 -0400 Received: by mail-wr1-x443.google.com with SMTP id v8so20446181wrt.2 for ; Mon, 14 Oct 2019 09:19:30 -0700 (PDT) Received: from 8c859074c0ff.ant.amazon.com.com (bzq-79-178-11-117.red.bezeqint.net. [79.178.11.117]) by smtp.gmail.com with ESMTPSA id c132sm28050861wme.27.2019.10.14.09.19.25 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 14 Oct 2019 09:19:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=KnzwXm9DGa8updfHvfNXSEz/qG/OHlkhJSqLyJjiNdY=; b=V9AQeyhC0l3o2Sz99RSspTvObtz//epdo3L1D+Iq0fMMo4xqVZqzQ3PODkN2eeeyi1 bdZH3X6/ER2k7U36KCw7BsmEXfv/uubWylmjIPBUY6/nuxytosAwXKuITyl9Zg0sGOTS Mhob5VhyyJMPX0iQg8XN/ANIbDR67QgEXCa/bqaO69xJQqndSW/yxDEtrRrVlRvNQ1Tj Oj7f26B6l927I56GifcZcFGQnHYSMRaeCC8vkJgCscN7xXCeGZg/DgCjkEAU4Q7MpDNC 3GYaB45S0ioTdT43FjiTkDEVIZEUDtQ2eGQF3WwdVxyA2qEX6Ajr9KQ4VcCBLzXHR6QE ArUg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=KnzwXm9DGa8updfHvfNXSEz/qG/OHlkhJSqLyJjiNdY=; b=TGMw99tWi2nZFd7ue+G2UeRWKr7tsFGXfAK/NUM6FLJzIMPluyp61+oKtP8juZdCqm jfTqiF3Tjs0+xgQMyMmpQYSGnisHpyqskVAjalwAYcrSVngjNZ7EJXEOG9sMbBkDG+W6 4sDk+7D0qmXLSjVE4igpLfTLG6dngxJ5Ph+UlKQBK0/DamlWJBOzfqEA1pymAl+R99f2 LAS6lssiV4xe+bOLXj0EUTNZbxPoxUi/uz7syLn/5JiSqKLflhkaFiapOdJGPl0RpcLi AM0mpKKtHNrIHPj58TE0Y6wjz5Qkkzqv0SBEuZLVLMPG4EDZx6Xou3ErG43zYyvM3jLF KBYQ== X-Gm-Message-State: APjAAAUIdmxp/Nj0fZi1Yg9GltmtZgfOOK4kYZhKejvs+fLXY705CYkr dkDXr3Ax9DGKVly3HPuPX3nQUsAT8WE= X-Google-Smtp-Source: APXvYqzPX1hvRWnwVOrjYr3/58exYvLASORxwQfq1ccTZt0bUuVrg7+sMoiZLEEVrUmaaUsB1tcb7A== X-Received: by 2002:a5d:52c4:: with SMTP id r4mr25425502wrv.168.1571069969294; Mon, 14 Oct 2019 09:19:29 -0700 (PDT) From: Michael Rolnik To: qemu-devel@nongnu.org Subject: [PATCH v32 11/13] target/avr: Add example board configuration Date: Mon, 14 Oct 2019 19:18:41 +0300 Message-Id: <20191014161843.84845-12-mrolnik@gmail.com> X-Mailer: git-send-email 2.17.2 (Apple Git-113) In-Reply-To: <20191014161843.84845-1-mrolnik@gmail.com> References: <20191014161843.84845-1-mrolnik@gmail.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::443 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: thuth@redhat.com, Michael Rolnik , richard.henderson@linaro.org, dovgaluk@ispras.ru, imammedo@redhat.com, philmd@redhat.com, aleksandar.m.mail@gmail.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" A simple board setup that configures an AVR CPU to run a given firmware ima= ge. This is all that's useful to implement without peripheral emulation as AVR = CPUs include a lot of on-board peripherals. NOTE: this is not a real board !!!! NOTE: it's used for CPU testing!!!! Signed-off-by: Michael Rolnik --- hw/Kconfig | 1 + hw/avr/Kconfig | 6 + hw/avr/Makefile.objs | 1 + hw/avr/sample.c | 282 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 290 insertions(+) create mode 100644 hw/avr/Kconfig create mode 100644 hw/avr/Makefile.objs create mode 100644 hw/avr/sample.c diff --git a/hw/Kconfig b/hw/Kconfig index b45db3c813..f185fcb19e 100644 --- a/hw/Kconfig +++ b/hw/Kconfig @@ -42,6 +42,7 @@ source watchdog/Kconfig # arch Kconfig source arm/Kconfig source alpha/Kconfig +source avr/Kconfig source cris/Kconfig source hppa/Kconfig source i386/Kconfig diff --git a/hw/avr/Kconfig b/hw/avr/Kconfig new file mode 100644 index 0000000000..92aa1e6afb --- /dev/null +++ b/hw/avr/Kconfig @@ -0,0 +1,6 @@ +config AVR_SAMPLE + bool + select AVR_TIMER16 + select AVR_USART + select AVR_MASK + select UNIMP diff --git a/hw/avr/Makefile.objs b/hw/avr/Makefile.objs new file mode 100644 index 0000000000..626b7064b3 --- /dev/null +++ b/hw/avr/Makefile.objs @@ -0,0 +1 @@ +obj-y +=3D sample.o diff --git a/hw/avr/sample.c b/hw/avr/sample.c new file mode 100644 index 0000000000..2295ec1b79 --- /dev/null +++ b/hw/avr/sample.c @@ -0,0 +1,282 @@ +/* + * QEMU AVR CPU + * + * Copyright (c) 2019 Michael Rolnik + * + * 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 + * + */ + +/* + * NOTE: + * This is not a real AVR board, this is an example! + * The CPU is an approximation of an ATmega2560, but is missing vario= us + * built-in peripherals. + * + * This example board loads provided binary file into flash memory and + * executes it from 0x00000000 address in the code memory space. + * + * Currently used for AVR CPU validation + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "cpu.h" +#include "hw/hw.h" +#include "sysemu/sysemu.h" +#include "sysemu/qtest.h" +#include "ui/console.h" +#include "hw/boards.h" +#include "hw/loader.h" +#include "qemu/error-report.h" +#include "exec/address-spaces.h" +#include "include/hw/sysbus.h" +#include "include/hw/char/avr_usart.h" +#include "include/hw/timer/avr_timer16.h" +#include "include/hw/misc/avr_mask.h" +#include "elf.h" +#include "hw/misc/unimp.h" + +#define SIZE_FLASH 0x00040000 +#define SIZE_SRAM 0x00002000 +/* + * Size of additional "external" memory, as if the AVR were configured to = use + * an external RAM chip. + * Note that the configuration registers that normally enable this feature= are + * unimplemented. + */ +#define SIZE_EXMEM 0x00000000 + +/* Offsets of peripherals in emulated memory space (i.e. not host addresse= s) */ +#define PRR0_BASE 0x64 +#define PRR1_BASE 0x65 +#define USART_BASE 0xc0 +#define TIMER1_BASE 0x80 +#define TIMER1_IMSK_BASE 0x6f +#define TIMER1_IFR_BASE 0x36 + +/* Interrupt numbers used by peripherals */ +#define USART_RXC_IRQ 24 +#define USART_DRE_IRQ 25 +#define USART_TXC_IRQ 26 + +#define TIMER1_CAPT_IRQ 15 +#define TIMER1_COMPA_IRQ 16 +#define TIMER1_COMPB_IRQ 17 +#define TIMER1_COMPC_IRQ 18 +#define TIMER1_OVF_IRQ 19 + +/* Power reduction */ +#define PRR1_BIT_PRTIM5 0x05 /* Timer/Counter5 */ +#define PRR1_BIT_PRTIM4 0x04 /* Timer/Counter4 */ +#define PRR1_BIT_PRTIM3 0x03 /* Timer/Counter3 */ +#define PRR1_BIT_PRUSART3 0x02 /* USART3 */ +#define PRR1_BIT_PRUSART2 0x01 /* USART2 */ +#define PRR1_BIT_PRUSART1 0x00 /* USART1 */ + +#define PRR0_BIT_PRTWI 0x06 /* TWI */ +#define PRR0_BIT_PRTIM2 0x05 /* Timer/Counter2 */ +#define PRR0_BIT_PRTIM0 0x04 /* Timer/Counter0 */ +#define PRR0_BIT_PRTIM1 0x03 /* Timer/Counter1 */ +#define PRR0_BIT_PRSPI 0x02 /* Serial Peripheral Interface */ +#define PRR0_BIT_PRUSART0 0x01 /* USART0 */ +#define PRR0_BIT_PRADC 0x00 /* ADC */ + +typedef struct { + MachineClass parent; +} SampleMachineClass; + +typedef struct { + MachineState parent; + MemoryRegion *ram; + MemoryRegion *flash; + AVRUsartState *usart0; + AVRTimer16State *timer1; + AVRMaskState *prr[2]; +} SampleMachineState; + +#define TYPE_SAMPLE_MACHINE MACHINE_TYPE_NAME("sample") + +#define SAMPLE_MACHINE(obj) \ + OBJECT_CHECK(SampleMachineState, obj, TYPE_SAMPLE_MACHINE) +#define SAMPLE_MACHINE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(SampleMachineClass, obj, TYPE_SAMPLE_MACHINE) +#define SAMPLE_MACHINE_CLASS(klass) \ + OBJECT_CLASS_CHECK(SampleMachineClass, klass, TYPE_SAMPLE_MACHINE) + +static void sample_init(MachineState *machine) +{ + SampleMachineState *sms =3D SAMPLE_MACHINE(machine); + MemoryRegion *system_memory =3D get_system_memory(); + AVRCPU *cpu; + const char *firmware =3D NULL; + const char *filename; + int bytes_loaded; + SysBusDevice *busdev; + DeviceState *cpudev; + + system_memory =3D get_system_memory(); + sms->ram =3D g_new(MemoryRegion, 1); + sms->flash =3D g_new(MemoryRegion, 1); + + cpu =3D AVR_CPU(cpu_create(machine->cpu_type)); + cpudev =3D DEVICE(cpu); + + + memory_region_init_rom(sms->flash, NULL, "avr.flash", SIZE_FLASH, + &error_fatal); + memory_region_add_subregion(system_memory, OFFSET_CODE, sms->flash); + + /* following are atmel2560 device */ + create_unimplemented_device("usart 3", OFFSET_DATA + 0x0130, 0x0007); + create_unimplemented_device("timer-counter-16bit 5", + OFFSET_DATA + 0x0120, 0x000e); + create_unimplemented_device("gpio L", OFFSET_DATA + 0x0109, 0x0003); + create_unimplemented_device("gpio K", OFFSET_DATA + 0x0106, 0x0003); + create_unimplemented_device("gpio J", OFFSET_DATA + 0x0103, 0x0003); + create_unimplemented_device("gpio H", OFFSET_DATA + 0x0100, 0x0003); + create_unimplemented_device("usart 2", OFFSET_DATA + 0x00d0, 0x0007); + create_unimplemented_device("usart 1", OFFSET_DATA + 0x00c8, 0x0007); + create_unimplemented_device("usart 0", OFFSET_DATA + 0x00c0, 0x0007); + create_unimplemented_device("twi", OFFSET_DATA + 0x00b8, 0x0006); + create_unimplemented_device("timer-counter-async-8bit 2", + OFFSET_DATA + 0x00b0, 0x0007); + create_unimplemented_device("timer-counter-16bit 4", + OFFSET_DATA + 0x00a0, 0x000e); + create_unimplemented_device("timer-counter-16bit 3", + OFFSET_DATA + 0x0090, 0x000e); + create_unimplemented_device("timer-counter-16bit 1", + OFFSET_DATA + 0x0080, 0x000e); + create_unimplemented_device("ac / adc", + OFFSET_DATA + 0x0078, 0x0008); + create_unimplemented_device("ext-mem-iface", + OFFSET_DATA + 0x0074, 0x0002); + create_unimplemented_device("int-controller", + OFFSET_DATA + 0x0068, 0x000c); + create_unimplemented_device("sys", + OFFSET_DATA + 0x0060, 0x0007); + create_unimplemented_device("spi", + OFFSET_DATA + 0x004c, 0x0003); + create_unimplemented_device("ext-mem-iface", + OFFSET_DATA + 0x004a, 0x0002); + create_unimplemented_device("timer-counter-pwm-8bit 0", + OFFSET_DATA + 0x0043, 0x0006); + create_unimplemented_device("ext-mem-iface", + OFFSET_DATA + 0x003e, 0x0005); + create_unimplemented_device("int-controller", + OFFSET_DATA + 0x0035, 0x0009); + create_unimplemented_device("gpio G", OFFSET_DATA + 0x0032, 0x0003); + create_unimplemented_device("gpio F", OFFSET_DATA + 0x002f, 0x0003); + create_unimplemented_device("gpio E", OFFSET_DATA + 0x002c, 0x0003); + create_unimplemented_device("gpio D", OFFSET_DATA + 0x0029, 0x0003); + create_unimplemented_device("gpio C", OFFSET_DATA + 0x0026, 0x0003); + create_unimplemented_device("gpio B", OFFSET_DATA + 0x0023, 0x0003); + create_unimplemented_device("gpio A", OFFSET_DATA + 0x0020, 0x0003); + + memory_region_allocate_system_memory( + sms->ram, NULL, "avr.ram", SIZE_SRAM + SIZE_EXMEM); + memory_region_add_subregion(system_memory, OFFSET_DATA + 0x200, sms->r= am); + + /* Power Reduction built-in peripheral */ + sms->prr[0] =3D AVR_MASK(sysbus_create_simple(TYPE_AVR_MASK, + OFFSET_DATA + PRR0_BASE, NULL)); + sms->prr[1] =3D AVR_MASK(sysbus_create_simple(TYPE_AVR_MASK, + OFFSET_DATA + PRR1_BASE, NULL)); + + /* USART 0 built-in peripheral */ + sms->usart0 =3D AVR_USART(object_new(TYPE_AVR_USART)); + busdev =3D SYS_BUS_DEVICE(sms->usart0); + qdev_prop_set_chr(DEVICE(sms->usart0), "chardev", serial_hd(0)); + object_property_set_bool(OBJECT(sms->usart0), true, "realized", + &error_fatal); + sysbus_mmio_map(busdev, 0, OFFSET_DATA + USART_BASE); + /* + * These IRQ numbers don't match the datasheet because we're counting = from + * zero and not including reset. + */ + sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(cpudev, USART_RXC_IRQ)); + sysbus_connect_irq(busdev, 1, qdev_get_gpio_in(cpudev, USART_DRE_IRQ)); + sysbus_connect_irq(busdev, 2, qdev_get_gpio_in(cpudev, USART_TXC_IRQ)); + sysbus_connect_irq(SYS_BUS_DEVICE(sms->prr[1]), PRR1_BIT_PRUSART1, + qdev_get_gpio_in(DEVICE(sms->usart0), 0)); + + /* Timer 1 built-in periphal */ + sms->timer1 =3D AVR_TIMER16(object_new(TYPE_AVR_TIMER16)); + object_property_set_bool(OBJECT(sms->timer1), true, "realized", + &error_fatal); + busdev =3D SYS_BUS_DEVICE(sms->timer1); + sysbus_mmio_map(busdev, 0, OFFSET_DATA + TIMER1_BASE); + sysbus_mmio_map(busdev, 1, OFFSET_DATA + TIMER1_IMSK_BASE); + sysbus_mmio_map(busdev, 2, OFFSET_DATA + TIMER1_IFR_BASE); + sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(cpudev, TIMER1_CAPT_IRQ= )); + sysbus_connect_irq(busdev, 1, qdev_get_gpio_in(cpudev, TIMER1_COMPA_IR= Q)); + sysbus_connect_irq(busdev, 2, qdev_get_gpio_in(cpudev, TIMER1_COMPB_IR= Q)); + sysbus_connect_irq(busdev, 3, qdev_get_gpio_in(cpudev, TIMER1_COMPC_IR= Q)); + sysbus_connect_irq(busdev, 4, qdev_get_gpio_in(cpudev, TIMER1_OVF_IRQ)= ); + sysbus_connect_irq(SYS_BUS_DEVICE(sms->prr[0]), PRR0_BIT_PRTIM1, + qdev_get_gpio_in(DEVICE(sms->timer1), 0)); + + /* Load firmware (contents of flash) trying to auto-detect format */ + firmware =3D machine->firmware; + if (firmware !=3D NULL) { + filename =3D qemu_find_file(QEMU_FILE_TYPE_BIOS, firmware); + if (filename =3D=3D NULL) { + error_report("Unable to find %s", firmware); + exit(1); + } + + bytes_loaded =3D load_elf( + filename, NULL, NULL, NULL, NULL, NULL, NULL, 0, EM_NONE, 0, 0= ); + if (bytes_loaded < 0) { + bytes_loaded =3D load_image_targphys( + filename, OFFSET_CODE, SIZE_FLASH); + } + if (bytes_loaded < 0) { + error_report( + "Unable to load firmware image %s as ELF or raw binary", + firmware); + exit(1); + } + } +} + +static void sample_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc =3D MACHINE_CLASS(oc); + + mc->desc =3D "AVR sample/example board (ATmega2560)"; + mc->init =3D sample_init; + mc->default_cpus =3D 1; + mc->min_cpus =3D mc->default_cpus; + mc->max_cpus =3D mc->default_cpus; + mc->default_cpu_type =3D "avr6-avr-cpu"; /* ATmega2560. */ + mc->is_default =3D 1; +} + +static const TypeInfo sample_info =3D { + .name =3D TYPE_SAMPLE_MACHINE, + .parent =3D TYPE_MACHINE, + .instance_size =3D sizeof(SampleMachineState), + .class_size =3D sizeof(SampleMachineClass), + .class_init =3D sample_class_init, +}; + +static void sample_machine_init(void) +{ + type_register_static(&sample_info); +} + +type_init(sample_machine_init); --=20 2.17.2 (Apple Git-113) From nobody Tue May 7 17:09:40 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1571074587; cv=none; d=zoho.com; s=zohoarc; b=Fp8gS9MLw6FuLyG9U9V4cRe9/F+HHev545MlJTl2+OzR3nLzZUMYPbXa6KglFM/ne5MXd/HaOYhwy6ze7M15wvdg5TgWQCU3l6+DRT9ShvwjRx3V7oIrR/tI3O1iJQbfYA6QVyGNxLRArISfsdLzg8ri0VAeo4rVokpzpAI51AY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1571074587; h=Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:Message-ID:References:Sender:Subject:To; bh=SMsddy6aZ63CgsEepIUcm6WyV0wXdBfVOcMIs69xOFY=; b=UXLMKydIJqjm7qY0h/HqcHc7ouk+glNH7P9qiiSvjuC3jADRlnd7yTiheIsnrBIpJ6xSE11Jx7NI7i0gv9ieiuUa4UWPKPdCri065Hgof7Hp9fYtU+551iwYViH4N4RtNKV7ugXykn/Gx4k/WD5SNmIQxcKFk0hZpPe+9ykA6gE= ARC-Authentication-Results: i=1; mx.zoho.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1571074587583254.4383616433547; Mon, 14 Oct 2019 10:36:27 -0700 (PDT) Received: from localhost ([::1]:54686 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iK4Gg-0003QM-Du for importer@patchew.org; Mon, 14 Oct 2019 13:36:26 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:39917) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iK34N-0006bP-7r for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:41 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iK34H-0007aB-Lw for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:39 -0400 Received: from mail-wr1-x441.google.com ([2a00:1450:4864:20::441]:39425) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1iK34H-0007Zz-CG for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:33 -0400 Received: by mail-wr1-x441.google.com with SMTP id r3so20447732wrj.6 for ; Mon, 14 Oct 2019 09:19:33 -0700 (PDT) Received: from 8c859074c0ff.ant.amazon.com.com (bzq-79-178-11-117.red.bezeqint.net. [79.178.11.117]) by smtp.gmail.com with ESMTPSA id c132sm28050861wme.27.2019.10.14.09.19.30 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 14 Oct 2019 09:19:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=SMsddy6aZ63CgsEepIUcm6WyV0wXdBfVOcMIs69xOFY=; b=fgMlSlf9RP6uuh5FTf0nJgK6ou6aeP2SvK3kT0FIxAa8ZwNgW7rC4rj2TdYKm1llcH XSw4OGUXHkppwSYrfX/dKue7w2urfEolr4FhEKXFT3zVShgugc9Qnbw3jYVpwP1maUmX YN88cAyuOm48HlZLmVbhyn4RFhLigTPQ0+SxDoE9PugiugXbqJbgk4KMD01iXb1l77mk jyz+CKzUqXFnZqI2I7gKmZau7v2QlCUBxEL1BEGoyIlyFtq9abfxmiwNHxuDAybJO2DI 9wRZTzOq3gh7u6Qt9wazIErXZdCf+cxejg1W0z6bHNUzQB+t0LM4K/YRpi50K66jT3Bm +tIw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=SMsddy6aZ63CgsEepIUcm6WyV0wXdBfVOcMIs69xOFY=; b=MKzEdnqBr11cOiOsFm9jh531NpXWBxk7kwNSikwnR0yvdz226aEOWHeF0JyqiAkGho OGPM7w1VAFI61XnBATY6SZQCdFg6Ps/UFu5Yuij/ALD9TceRkvoB4keTC5Pu4xCK4Jv6 a1CLj11nd81URxcVygtmEoV+2IJn9sa1Ap4i4qIAa7/e400gbIZkV8Ii7Me7LjjXMLMl AGxVD63VtUg5glnqGtAByWQAEsmGfOFRxFITXSXVtTn/Hx+DsSU8KjqJ1+o4T8rBaaFC hVGPOkQMwruUOxAf7edk3u5dRVH3rhUsUkWcAIGceNXLDVNNP0J130KO2hps07x1N5Yq QyWA== X-Gm-Message-State: APjAAAW0YOSy153Zp8jfIgA4y+lKbl8Lkaxmr8uZ/z+pTbue9lNR3Pla uCS5pp+KQ+z9h2Z8BVEDglh/DUhPQ5U= X-Google-Smtp-Source: APXvYqylgnNM/+ELhRqYA6NdMZi1MEzv2hV5A9BPiMNyJ8BXA5sas59d24rmcczAhulGdgNlpJgnOQ== X-Received: by 2002:adf:dfc6:: with SMTP id q6mr26770677wrn.207.1571069972019; Mon, 14 Oct 2019 09:19:32 -0700 (PDT) From: Michael Rolnik To: qemu-devel@nongnu.org Subject: [PATCH v32 12/13] target/avr: Register AVR support with the rest of QEMU, the build system, and the WMAINTAINERS file Date: Mon, 14 Oct 2019 19:18:42 +0300 Message-Id: <20191014161843.84845-13-mrolnik@gmail.com> X-Mailer: git-send-email 2.17.2 (Apple Git-113) In-Reply-To: <20191014161843.84845-1-mrolnik@gmail.com> References: <20191014161843.84845-1-mrolnik@gmail.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::441 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: thuth@redhat.com, Michael Rolnik , richard.henderson@linaro.org, dovgaluk@ispras.ru, imammedo@redhat.com, philmd@redhat.com, aleksandar.m.mail@gmail.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Signed-off-by: Michael Rolnik --- MAINTAINERS | 9 +++++++++ arch_init.c | 2 ++ configure | 7 +++++++ default-configs/avr-softmmu.mak | 5 +++++ include/disas/dis-asm.h | 6 ++++++ include/sysemu/arch_init.h | 1 + qapi/machine.json | 3 ++- target/avr/Makefile.objs | 33 +++++++++++++++++++++++++++++++++ tests/machine-none-test.c | 1 + 9 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 default-configs/avr-softmmu.mak create mode 100644 target/avr/Makefile.objs diff --git a/MAINTAINERS b/MAINTAINERS index 3ca814850e..8c1a616958 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -163,6 +163,15 @@ S: Maintained F: hw/arm/smmu* F: include/hw/arm/smmu* =20 +AVR TCG CPUs +M: Michael Rolnik +S: Maintained +F: target/avr/ +F: hw/misc/avr_mask.c +F: hw/char/avr_usart.c +F: hw/timer/avr_timer16.c +F: hw/avr/ + CRIS TCG CPUs M: Edgar E. Iglesias S: Maintained diff --git a/arch_init.c b/arch_init.c index 0a1531124c..fb308aa802 100644 --- a/arch_init.c +++ b/arch_init.c @@ -85,6 +85,8 @@ int graphic_depth =3D 32; #define QEMU_ARCH QEMU_ARCH_UNICORE32 #elif defined(TARGET_XTENSA) #define QEMU_ARCH QEMU_ARCH_XTENSA +#elif defined(TARGET_AVR) +#define QEMU_ARCH QEMU_ARCH_AVR #endif =20 const uint32_t arch_type =3D QEMU_ARCH; diff --git a/configure b/configure index 08ca4bcb46..e3b673b8cc 100755 --- a/configure +++ b/configure @@ -7444,6 +7444,10 @@ case "$target_name" in mttcg=3D"yes" gdb_xml_files=3D"aarch64-core.xml aarch64-fpu.xml arm-core.xml arm-vfp= .xml arm-vfp3.xml arm-neon.xml" ;; + avr) + gdb_xml_files=3D"avr-cpu.xml" + target_compiler=3D$cross_cc_avr + ;; cris) ;; hppa) @@ -7663,6 +7667,9 @@ for i in $ARCH $TARGET_BASE_ARCH ; do disas_config "ARM_A64" fi ;; + avr) + disas_config "AVR" + ;; cris) disas_config "CRIS" ;; diff --git a/default-configs/avr-softmmu.mak b/default-configs/avr-softmmu.= mak new file mode 100644 index 0000000000..d1e1c28118 --- /dev/null +++ b/default-configs/avr-softmmu.mak @@ -0,0 +1,5 @@ +# Default configuration for avr-softmmu + +# Boards: +# +CONFIG_AVR_SAMPLE=3Dy diff --git a/include/disas/dis-asm.h b/include/disas/dis-asm.h index e9c7dd8eb4..8bedce17ac 100644 --- a/include/disas/dis-asm.h +++ b/include/disas/dis-asm.h @@ -211,6 +211,12 @@ enum bfd_architecture #define bfd_mach_m32r 0 /* backwards compatibility */ bfd_arch_mn10200, /* Matsushita MN10200 */ bfd_arch_mn10300, /* Matsushita MN10300 */ + bfd_arch_avr, /* Atmel AVR microcontrollers. */ +#define bfd_mach_avr1 1 +#define bfd_mach_avr2 2 +#define bfd_mach_avr3 3 +#define bfd_mach_avr4 4 +#define bfd_mach_avr5 5 bfd_arch_cris, /* Axis CRIS */ #define bfd_mach_cris_v0_v10 255 #define bfd_mach_cris_v32 32 diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h index 62c6fe4cf1..893df26ce2 100644 --- a/include/sysemu/arch_init.h +++ b/include/sysemu/arch_init.h @@ -24,6 +24,7 @@ enum { QEMU_ARCH_NIOS2 =3D (1 << 17), QEMU_ARCH_HPPA =3D (1 << 18), QEMU_ARCH_RISCV =3D (1 << 19), + QEMU_ARCH_AVR =3D (1 << 20), }; =20 extern const uint32_t arch_type; diff --git a/qapi/machine.json b/qapi/machine.json index ca26779f1a..1fa2917ba9 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -21,11 +21,12 @@ # is true even for "qemu-system-x86_64". # # ppcemb: dropped in 3.1 +# avr: since 4.2 # # Since: 3.0 ## { 'enum' : 'SysEmuTarget', - 'data' : [ 'aarch64', 'alpha', 'arm', 'cris', 'hppa', 'i386', 'lm32', + 'data' : [ 'aarch64', 'alpha', 'arm', 'avr', 'cris', 'hppa', 'i386', 'lm= 32', 'm68k', 'microblaze', 'microblazeel', 'mips', 'mips64', 'mips64el', 'mipsel', 'moxie', 'nios2', 'or1k', 'ppc', 'ppc64', 'riscv32', 'riscv64', 's390x', 'sh4', diff --git a/target/avr/Makefile.objs b/target/avr/Makefile.objs new file mode 100644 index 0000000000..2976affd95 --- /dev/null +++ b/target/avr/Makefile.objs @@ -0,0 +1,33 @@ +# +# QEMU AVR CPU +# +# Copyright (c) 2019 Michael Rolnik +# +# 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 +# +# + +DECODETREE =3D $(SRC_PATH)/scripts/decodetree.py +decode-y =3D $(SRC_PATH)/target/avr/insn.decode + +target/avr/decode_insn.inc.c: $(decode-y) $(DECODETREE) + $(call quiet-command, \ + $(PYTHON) $(DECODETREE) -o $@ --decode decode_insn --insnwidth 16 $<, \ + "GEN", $(TARGET_DIR)$@) + +target/avr/translate.o: target/avr/decode_insn.inc.c + +obj-y +=3D translate.o cpu.o helper.o +obj-y +=3D gdbstub.o +obj-$(CONFIG_SOFTMMU) +=3D machine.o diff --git a/tests/machine-none-test.c b/tests/machine-none-test.c index 5953d31755..3e5c74e73e 100644 --- a/tests/machine-none-test.c +++ b/tests/machine-none-test.c @@ -27,6 +27,7 @@ static struct arch2cpu cpus_map[] =3D { /* tested targets list */ { "arm", "cortex-a15" }, { "aarch64", "cortex-a57" }, + { "avr", "avr6-avr-cpu" }, { "x86_64", "qemu64,apic-id=3D0" }, { "i386", "qemu32,apic-id=3D0" }, { "alpha", "ev67" }, --=20 2.17.2 (Apple Git-113) From nobody Tue May 7 17:09:40 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1571074472; cv=none; d=zoho.com; s=zohoarc; b=ALwZfPTtf5N+zklLHBk5U9906LC2QCa2aZdGE60Gw4+jwNogFklTHoLd1mrSnApQ+i8m1HCV0UsRqWmmkZZ/8r3c08VWQHdwqDo2c9FcJN/LfBrGgst+pNd9v5Fhd1kXlWAUSnuYpUW6doKl43TxY41+rTJICsvAl0HYxn83GBQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1571074472; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=9d/uDGv85dLEv33nEDGWywNGXN8GQJeP0QFNxDLvG8o=; b=FVE60yacUi4K8Ft5knrFH3u8i/ozWUDgq2oGBbOFU7973IiLunS0w5rY3foGASuq3U0Ps7404wHjY7r4Q7NsHEOgZ12qLSKcTYIDSQryVw57lMHeBk8aul2CdH1SM7MethvIRe8mu0u8UOBnau9vAw+1HHvX5VziBqfUbTuVzWo= ARC-Authentication-Results: i=1; mx.zoho.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 157107447235221.765502016505252; Mon, 14 Oct 2019 10:34:32 -0700 (PDT) Received: from localhost ([::1]:54648 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iK4Ep-0000am-2S for importer@patchew.org; Mon, 14 Oct 2019 13:34:31 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:39909) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iK34K-0006Xz-Li for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:37 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iK34J-0007aP-9i for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:36 -0400 Received: from mail-wr1-x429.google.com ([2a00:1450:4864:20::429]:42057) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1iK34J-0007aF-2s for qemu-devel@nongnu.org; Mon, 14 Oct 2019 12:19:35 -0400 Received: by mail-wr1-x429.google.com with SMTP id n14so20393625wrw.9 for ; Mon, 14 Oct 2019 09:19:35 -0700 (PDT) Received: from 8c859074c0ff.ant.amazon.com.com (bzq-79-178-11-117.red.bezeqint.net. [79.178.11.117]) by smtp.gmail.com with ESMTPSA id c132sm28050861wme.27.2019.10.14.09.19.32 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 14 Oct 2019 09:19:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=9d/uDGv85dLEv33nEDGWywNGXN8GQJeP0QFNxDLvG8o=; b=GfJKuOq4ESGuaUxpx+6ovR1uYdwow39CrkmXDFFF/bF8qfvzbw/V76Htztk3tEGUiD uXjBBEvEiM/QvfKy9xhsTnkK2IOm5GYq99CI8K01FGaRCcFtvG4qHFAgyuTBj1vq3Awn s5w1wYpI1c8hPqSHVrSCqG7FL0srrALZQ8UKG52/gaVt+qPqzlM7dEsBL0IEMhbsNXCx SeUtTGcppS/vD5bPNY+q6re4uZkDnrMJFNxjdDNuhRgHW1MVGR8UhgaBB7fV1vBgScNN e1/KcNcjiy3+3vGYUQrqmnPVZakLdOT8jpfMu8CZgICbxGvTGLxJSiadXuSqY8PxN1Ma CJmQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=9d/uDGv85dLEv33nEDGWywNGXN8GQJeP0QFNxDLvG8o=; b=V1fIfnFFOO/rDGt7Jaj8E/quS88lcWaYZ0/hqAnry/CT8Y4WYlUGwGLDNU3f6AxM7i DOhVZZQixmYDDmABCRb1/K3a7pJKixF+U9ZWpUrzt2t0cOi3F2aut7sL5nfXEShr+A+C xltkGJFi30PzvEj51aRKasFQjqE/oBO8Dm1pWLPnt/hVX/LyISYnXO/kcXWzLOch9xM3 WjEk9K4yvP9Mz6fQdk9rJ54+a+ZcBg0/FtjG8F8Z3fgUIlOnHIjxKseyy4rhFJGqowGY Dk6JyM+KyIKbb2on6LDmuNcjUzfET2/8AbzzucUL0lzcxzPJhUsPwpygERIqszFq8Y1i Kscg== X-Gm-Message-State: APjAAAWY6lYk1plgt5tFUl/kMTOdlDf8GzhXipohHGOcAwYt4rAnFPQ4 ptrk68p+MiuaH9VtLjch2ZUqTdss/pE= X-Google-Smtp-Source: APXvYqx0sUpqbezYqdztaupuNiNumTWPZxgpWggD7L2GJZKfqCF1bKGWLyLBci7GbL4SWevMbONfRg== X-Received: by 2002:adf:dec9:: with SMTP id i9mr13877325wrn.230.1571069973624; Mon, 14 Oct 2019 09:19:33 -0700 (PDT) From: Michael Rolnik To: qemu-devel@nongnu.org Subject: [PATCH v32 13/13] target/avr: Add tests Date: Mon, 14 Oct 2019 19:18:43 +0300 Message-Id: <20191014161843.84845-14-mrolnik@gmail.com> X-Mailer: git-send-email 2.17.2 (Apple Git-113) In-Reply-To: <20191014161843.84845-1-mrolnik@gmail.com> References: <20191014161843.84845-1-mrolnik@gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::429 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: thuth@redhat.com, Michael Rolnik , richard.henderson@linaro.org, dovgaluk@ispras.ru, imammedo@redhat.com, philmd@redhat.com, aleksandar.m.mail@gmail.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) 1. Avocado test The test is based on https://github.com/seharris/qemu-avr-tests/tree/master/free-rtos/Demo demo which. If working correctly, prints 'ABCDEFGHIJKLMNOPQRSTUVWX' out. it also demostrates that timer and IRQ are working 2. Boot serial test Print out 'T' through serial port Signed-off-by: Michael Rolnik Reviewed-by: Philippe Mathieu-Daud=C3=A9 Tested-by: Philippe Mathieu-Daud=C3=A9 Acked-by: Thomas Huth --- tests/Makefile.include | 2 ++ tests/acceptance/machine_avr6.py | 36 ++++++++++++++++++++++++++++++++ tests/boot-serial-test.c | 10 +++++++++ 3 files changed, 48 insertions(+) create mode 100644 tests/acceptance/machine_avr6.py diff --git a/tests/Makefile.include b/tests/Makefile.include index 3543451ed3..376d7dfea3 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -199,6 +199,8 @@ check-qtest-i386-y +=3D tests/test-x86-cpuid-compat$(EX= ESUF) check-qtest-i386-y +=3D tests/numa-test$(EXESUF) check-qtest-x86_64-y +=3D $(check-qtest-i386-y) =20 +check-qtest-avr-y +=3D tests/boot-serial-test$(EXESUF) + check-qtest-alpha-y +=3D tests/boot-serial-test$(EXESUF) check-qtest-alpha-$(CONFIG_VGA) +=3D tests/display-vga-test$(EXESUF) =20 diff --git a/tests/acceptance/machine_avr6.py b/tests/acceptance/machine_av= r6.py new file mode 100644 index 0000000000..0601080b01 --- /dev/null +++ b/tests/acceptance/machine_avr6.py @@ -0,0 +1,36 @@ +import logging +import time +import distutils.spawn + +from avocado import skipUnless +from avocado_qemu import Test +from avocado.utils import process + +class AVR6Machine(Test): + timeout =3D 5 + + def test_freertos(self): + """ + :avocado: tags=3Darch:avr + :avocado: tags=3Dmachine:sample + """ + """ + https://github.com/seharris/qemu-avr-tests/raw/master/free-rtos/De= mo/AVR_ATMega2560_GCC/demo.elf + constantly prints out 'ABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRS= TUVWX' + """ + rom_url =3D 'https://github.com/seharris/qemu-avr-tests' + rom_url +=3D '/raw/master/free-rtos/Demo/AVR_ATMega2560_GCC/demo.e= lf' + rom_hash =3D '7eb521f511ca8f2622e0a3c5e8dd686efbb911d4' + rom_path =3D self.fetch_asset(rom_url, asset_hash=3Drom_hash) + + self.vm.set_machine('sample') + self.vm.add_args('-bios', rom_path) + self.vm.add_args('-nographic') + self.vm.launch() + + time.sleep(2) + self.vm.shutdown() + + match =3D 'ABCDEFGHIJKLMNOPQRSTUVWXABCDEFGHIJKLMNOPQRSTUVWX' + + self.assertIn(match, self.vm.get_log()) diff --git a/tests/boot-serial-test.c b/tests/boot-serial-test.c index d3a54a0ba5..1121ed0db2 100644 --- a/tests/boot-serial-test.c +++ b/tests/boot-serial-test.c @@ -16,6 +16,15 @@ #include "qemu/osdep.h" #include "libqtest.h" =20 +static const uint8_t bios_avr[] =3D { + 0x88, 0xe0, /* ldi r24, 0x08 */ + 0x80, 0x93, 0xc1, 0x00, /* sts 0x00C1, r24 ; Enable tx */ + 0x86, 0xe0, /* ldi r24, 0x06 */ + 0x80, 0x93, 0xc2, 0x00, /* sts 0x00C2, r24 ; Set the data bits to 8 */ + 0x84, 0xe5, /* ldi r24, 0x54 */ + 0x80, 0x93, 0xc6, 0x00, /* sts 0x00C6, r24 ; Output 'T' */ +}; + static const uint8_t kernel_mcf5208[] =3D { 0x41, 0xf9, 0xfc, 0x06, 0x00, 0x00, /* lea 0xfc060000,%a0 */ 0x10, 0x3c, 0x00, 0x54, /* move.b #'T',%d0 */ @@ -103,6 +112,7 @@ typedef struct testdef { =20 static testdef_t tests[] =3D { { "alpha", "clipper", "", "PCI:" }, + { "avr", "sample", "", "T", sizeof(bios_avr), NULL, bios_avr }, { "ppc", "ppce500", "", "U-Boot" }, { "ppc", "40p", "-vga none -boot d", "Trying cd:," }, { "ppc", "g3beige", "", "PowerPC,750" }, --=20 2.17.2 (Apple Git-113)