From nobody Mon Feb 9 10:37:31 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.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 (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1579827456; cv=none; d=zohomail.com; s=zohoarc; b=Gb3BfeAHCTmcHfhifiJU1ionp490HVtFC/8c7VYqoSEwHpfuJetVMTzrf89FIAjK1xq91howUzE6zRfh5f7RMpKY+JsIf2Q+zhVRGde8e+VkcsdZkrXz9rzolH/qVrOA0ZTvjHtDrseW4nCxMnMVEByUV1ipg/kQLg3BH/GfJTc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1579827456; 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=yEZWk0lG1Qw+t7F/fbLX1QbVSJjoK5uaV1TSNjYgFzs=; b=SCFLSwoQxnGTaoFionsL+zkPkuQebcEx95RRNUfp1L+a/22uVhcXgqTTl94gWtM30JgCr2W7OsDLyMwYouFG81FYZyx3l/whd12mtgeLfIeRJDr75FXw91Dv06fAeFPq4jHWGtK570c4h88pqhuo6Wt9nzjrE6d9QaAwAZUZP1E= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1579827456779292.5855394962605; Thu, 23 Jan 2020 16:57:36 -0800 (PST) Received: from localhost ([::1]:36082 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iunHz-0005rE-GO for importer@patchew.org; Thu, 23 Jan 2020 19:57:35 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:44240) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iunCV-0001aX-UP for qemu-devel@nongnu.org; Thu, 23 Jan 2020 19:52:00 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iunCR-00056S-El for qemu-devel@nongnu.org; Thu, 23 Jan 2020 19:51:55 -0500 Received: from mail-wr1-x441.google.com ([2a00:1450:4864:20::441]:38483) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1iunCR-00055T-1i; Thu, 23 Jan 2020 19:51:51 -0500 Received: by mail-wr1-x441.google.com with SMTP id y17so73767wrh.5; Thu, 23 Jan 2020 16:51:50 -0800 (PST) Received: from x1w.redhat.com (113.red-83-57-172.dynamicip.rima-tde.net. [83.57.172.113]) by smtp.gmail.com with ESMTPSA id s139sm4598271wme.35.2020.01.23.16.51.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 23 Jan 2020 16:51:48 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=yEZWk0lG1Qw+t7F/fbLX1QbVSJjoK5uaV1TSNjYgFzs=; b=TDPT22EeS1aQ9HmtlPqJhdUo/wgzgqxnH89q04rSQdPAoOjEznIZJCBiyar00h86E7 pdHCF2QYqiopqlFZjmnTU0USukTPy2XBMzv4qgPCvKtOQ3tA+57a0pePkmI2vMnFKGgT Uu3cmTObl8gK2FQnfuemNdMedFGgfxvhtSbRt/vHU6Cjn3dmXkRjCbXDzmEcaWWc5RRk uieIW+iln3kaebsYVw7DINjHDPkkF+FUF1V9HBoZc9bbsu6SSburoYfcUHwG9U+AtpQe Uhpprrg5iacfQ7caNspPh/g1pbK3ZWPqopcX/8IAmQX0xomCIIQ/xdRetMeU0PHVVxfx Zbpw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:content-transfer-encoding; bh=yEZWk0lG1Qw+t7F/fbLX1QbVSJjoK5uaV1TSNjYgFzs=; b=JBSJA795Rukp5ci1CMkuqYleI7997yGpWDIF8E9HqCHVyniOTF7m0kCpycHiyE/ARA 4qQB1BSCYTTq4eR085zsBz9BASWU6Do02ekFKf9eLl9tqgx/kU2Fe4sr4uY6s2OAeiru vkdWCG4XDA+DW4gAUH+hnsKMXM4ND+DXpue/ewipEbaUbut70OFGWu+Upgy7OUOii426 VmsjH1bSVUSXU1LgatwT7GCImVhadQgXOSqMRB5H0HOyuceW2RPYmeWqckV9fm2SUOqh BvNtOcApUjgsc2/GMc+Tzx65wTfrdfXV9cW615eGApfAxHVj9HlbTSX9IcRo2iYHsbxf qhcA== X-Gm-Message-State: APjAAAUanlb97tf5evle9nkphi7f1q3e1dl9za03ZdOVOq7cVyl+Qiym tFrgdBrTNSO4qCmcpMm6PRcGmzB3 X-Google-Smtp-Source: APXvYqwylTWHmzSg87p+/M0zNgqgqOLArvmyyjEoYYGZRjjMH93tIjQl5A1OBqH+Lynp+Nt/AjWnWQ== X-Received: by 2002:a5d:46c7:: with SMTP id g7mr824540wrs.11.1579827109093; Thu, 23 Jan 2020 16:51:49 -0800 (PST) From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= To: qemu-devel@nongnu.org, mrolnik@gmail.com, richard.henderson@linaro.org, me@xcancerberox.com.ar Subject: [PATCH rc2 06/25] target/avr: Add instruction translation - Data Transfer Instructions Date: Fri, 24 Jan 2020 01:51:12 +0100 Message-Id: <20200124005131.16276-7-f4bug@amsat.org> X-Mailer: git-send-email 2.21.1 In-Reply-To: <20200124005131.16276-1-f4bug@amsat.org> References: <20200124005131.16276-1-f4bug@amsat.org> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" 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::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: Laurent Vivier , Fam Zheng , S.E.Harris@kent.ac.uk, qemu-riscv@nongnu.org, Eduardo Habkost , Sagar Karandikar , dovgaluk@ispras.ru, Bastian Koppelmann , thuth@redhat.com, Markus Armbruster , =?UTF-8?q?Alex=20Benn=C3=A9e?= , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , Alistair Francis , imammedo@redhat.com, Paolo Bonzini , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Palmer Dabbelt , 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) From: Michael Rolnik This includes: - MOV, MOVW - LDI, LDS LDX LDY LDZ - LDDY, LDDZ - STS, STX STY STZ - STDY, STDZ - LPM, LPMX - ELPM, ELPMX - SPM, SPMX - IN, OUT - PUSH, POP - XCH - LAS, LAC LAT Signed-off-by: Michael Rolnik Tested-by: Philippe Mathieu-Daud=C3=A9 Message-Id: <20200118191416.19934-7-mrolnik@gmail.com> Signed-off-by: Richard Henderson --- target/avr/translate.c | 987 +++++++++++++++++++++++++++++++++++++++++ target/avr/insn.decode | 43 ++ 2 files changed, 1030 insertions(+) diff --git a/target/avr/translate.c b/target/avr/translate.c index 3d4005740a..4a62d9312a 100644 --- a/target/avr/translate.c +++ b/target/avr/translate.c @@ -1453,3 +1453,990 @@ static bool trans_BRBS(DisasContext *ctx, arg_BRBS = *a) ctx->bstate =3D DISAS_CHAIN; return true; } + +/* + * Data Transfer Instructions + */ + +/* + * 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]= */ + } +} + +/* + * 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; +} + +/* + * 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; +} + +/* + * 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; +} + +/* + * 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; +} + +/* + * Stores one byte indirect from a register to 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 spa= ce + * consists of the Register File only. The EEPROM has a separate address s= pace. + * + * 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 segment in devices with more than 64KB data spac= e, the + * RAMPX in register in the I/O area has to be changed. + * + * The X-pointer Register can either be left unchanged by the operation, o= r it + * can be post-incremented or pre-decremented. These features are especial= ly + * suited for accessing arrays, tables, and Stack Pointer usage of the + * X-pointer Register. Note that only the low byte of the X-pointer is upd= ated + * in devices with no more than 256 bytes data space. For such devices, th= e high + * byte of the pointer is not used by this instruction and can be used for= other + * purposes. The RAMPX Register in the I/O area is updated in parts with m= ore + * than 64KB data space or more than 64KB Program memory, and the incremen= t / + * decrement is added to the entire 24-bit address on such devices. + */ +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; +} + +/* + * Stores one byte indirect with or without displacement from a register t= o data + * space. For parts with SRAM, the data space consists of the Register Fil= e, I/O + * memory, and internal SRAM (and external SRAM if applicable). For parts + * without SRAM, the data space consists of the Register File only. The EE= PROM + * has a separate address space. + * + * The data location is pointed to by the Y (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 spac= e, the + * RAMPY in register in the I/O area has to be changed. + * + * The Y-pointer Register can either be left unchanged by the operation, o= r it + * can be post-incremented or pre-decremented. These features are especial= ly + * suited for accessing arrays, tables, and Stack Pointer usage of the Y-p= ointer + * Register. Note that only the low byte of the Y-pointer is updated in de= vices + * with no more than 256 bytes data space. For such devices, the high byte= of + * the pointer is 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 m= ore + * than 64KB data space or more than 64KB Program memory, and the incremen= t / + * decrement / displacement is added to the entire 24-bit address on such + * devices. + */ +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; +} + +/* + * Stores one byte indirect with or without displacement from a register t= o data + * space. For parts with SRAM, the data space consists of the Register Fil= e, I/O + * memory, and internal SRAM (and external SRAM if applicable). For parts + * without SRAM, the data space consists of the Register File only. The EE= PROM + * has a separate address space. + * + * The data location is pointed to by the Y (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 spac= e, the + * RAMPY in register in the I/O area has to be changed. + * + * The Y-pointer Register can either be left unchanged by the operation, o= r it + * can be post-incremented or pre-decremented. These features are especial= ly + * suited for accessing arrays, tables, and Stack Pointer usage of the Y-p= ointer + * Register. Note that only the low byte of the Y-pointer is updated in de= vices + * with no more than 256 bytes data space. For such devices, the high byte= of + * the pointer is 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 m= ore + * than 64KB data space or more than 64KB Program memory, and the incremen= t / + * decrement / displacement is added to the entire 24-bit address on such + * devices. + */ +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; +} + +/* + * 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 t= o read + * the Fuse and Lock bit values. + */ +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. + */ +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 devices. Refer to the devi= ce + * specific instruction set summary. + * + * Note: 1. R1 determines the instruction high byte, and R0 determines the + * instruction 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 Register is left unchanged by the operation. This instru= ction + * is especially suited 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 instru= ction + * 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] */ + tcg_gen_andc_tl(t1, t0, Rr); /* t1 =3D t0 & (0xff - Rr) =3D 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; +} diff --git a/target/avr/insn.decode b/target/avr/insn.decode index 32034c10d2..3f9304f8b0 100644 --- a/target/avr/insn.decode +++ b/target/avr/insn.decode @@ -115,3 +115,46 @@ SBIC 1001 1001 reg:5 bit:3 SBIS 1001 1011 reg:5 bit:3 BRBS 1111 00 ....... ... @op_bit_imm BRBC 1111 01 ....... ... @op_bit_imm + +# +# Data Transfer Instructions +# +MOV 0010 11 . ..... .... @op_rd_rr +MOVW 0000 0001 .... .... &rd_rr rd=3D%rd_d rr=3D%r= r_d +LDI 1110 .... .... .... @op_rd_imm8 +LDS 1001 000 ..... 0000 @ldst_s +LDX1 1001 000 rd:5 1100 +LDX2 1001 000 rd:5 1101 +LDX3 1001 000 rd:5 1110 +LDY2 1001 000 rd:5 1001 +LDY3 1001 000 rd:5 1010 +LDZ2 1001 000 rd:5 0001 +LDZ3 1001 000 rd:5 0010 +LDDY 10 . 0 .. 0 ..... 1 ... @ldst_d +LDDZ 10 . 0 .. 0 ..... 0 ... @ldst_d +STS 1001 001 ..... 0000 @ldst_s +STX1 1001 001 rr:5 1100 +STX2 1001 001 rr:5 1101 +STX3 1001 001 rr:5 1110 +STY2 1001 001 rd:5 1001 +STY3 1001 001 rd:5 1010 +STZ2 1001 001 rd:5 0001 +STZ3 1001 001 rd:5 0010 +STDY 10 . 0 .. 1 ..... 1 ... @ldst_d +STDZ 10 . 0 .. 1 ..... 0 ... @ldst_d +LPM1 1001 0101 1100 1000 +LPM2 1001 000 rd:5 0100 +LPMX 1001 000 rd:5 0101 +ELPM1 1001 0101 1101 1000 +ELPM2 1001 000 rd:5 0110 +ELPMX 1001 000 rd:5 0111 +SPM 1001 0101 1110 1000 +SPMX 1001 0101 1111 1000 +IN 1011 0 .. ..... .... @io_rd_imm +OUT 1011 1 .. ..... .... @io_rd_imm +PUSH 1001 001 rd:5 1111 +POP 1001 000 rd:5 1111 +XCH 1001 001 rd:5 0100 +LAC 1001 001 rd:5 0110 +LAS 1001 001 rd:5 0101 +LAT 1001 001 rd:5 0111 --=20 2.21.1