From patchwork Thu Jun 8 18:49:43 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Rolnik X-Patchwork-Id: 9776295 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 1394E6034B for ; Thu, 8 Jun 2017 18:57:10 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0081A28429 for ; Thu, 8 Jun 2017 18:57:10 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E86C1285A6; Thu, 8 Jun 2017 18:57:09 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 3F8AB28429 for ; Thu, 8 Jun 2017 18:57:07 +0000 (UTC) Received: from localhost ([::1]:51064 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dJ2cE-00025C-A2 for patchwork-qemu-devel@patchwork.kernel.org; Thu, 08 Jun 2017 14:57:06 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:47378) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dJ2Vp-0005yV-QC for qemu-devel@nongnu.org; Thu, 08 Jun 2017 14:50:34 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dJ2Vj-0001RP-Ro for qemu-devel@nongnu.org; Thu, 08 Jun 2017 14:50:28 -0400 Received: from mail-wm0-x241.google.com ([2a00:1450:400c:c09::241]:33634) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1dJ2Vj-0001RI-Dj for qemu-devel@nongnu.org; Thu, 08 Jun 2017 14:50:23 -0400 Received: by mail-wm0-x241.google.com with SMTP id x3so8675583wme.0 for ; Thu, 08 Jun 2017 11:50: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=rTGHPtxe/NMMb37xf2L7RfDThOmche7JGlEjaA0N/h0=; b=Chrk7snhnVj2AiPd+Ov+ec+kXfUZeFqiUp8oU2k/G4G3z5ohcCH/2DuLF7B9GqwGgO 6SJ68IO2/lID2wfSRFTX6Oj/3pKFEeanlM//nQDrtC1ZNpOw4R4Ggz4kY4FY3iJ9Amg6 j1wPGtGKfKXiUPn8kyZxAwqudLKb8tfLa5p6zkbZeoq38MWF34aUVQ056DJFWuy7KMvk u5/Zqler5P1f8dDn8XHDK3/0S4+1qTHzdfEZ1iY5xWrET+QYu6Gac1iSQOgtlVV4GMnE ZnOhoWV7PyCvBHIdC6DD8KSVecO3gIb9RDLl4UQf9ORd/nZRipuwgMmgPgcuBDa9rJoL nYHQ== 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=rTGHPtxe/NMMb37xf2L7RfDThOmche7JGlEjaA0N/h0=; b=AeLoK0+3kbBu/qlyAiCbveOHXRMizBSeUedu37CgSYHIIdDz2bKpbQZWoIJxczAKNl nv/vcgvQBcbA8BMb7F9OawK9IQZM+xDm9zTtrKit5GuBZ0v4eyhgCeXnczXFBqkBcL/6 p+LurMrpxInbXS4Dwu1bQ5vxxMyiWIshXGIPgqYTUuSnU81W8hA8i75m5ry1cKg22lw/ 3soE0nh2xbS6waQAWuibeE6t4NunqqWUA8Zx4yKw8XSXqdq6VthYaDbI7a0pg7PfRNDO r/Fq9A8nioeikfFTwfVyCNpl1ELdz79gLQQ+HYOautlMS2EGBKeLj0WBftn9UGXIMJqx XyBA== X-Gm-Message-State: AODbwcCXLFoW8CAByFbWrmFFSYjaIlczeK9NfR+19GCRL8ZCZHG1Fzdt ZzSfjQbBVixVyx37u3w= X-Received: by 10.80.145.198 with SMTP id h6mr30145157eda.108.1496947821747; Thu, 08 Jun 2017 11:50:21 -0700 (PDT) Received: from a0999b0126e1.ant.amazon.com ([2.53.26.197]) by smtp.gmail.com with ESMTPSA id z32sm2914198edb.8.2017.06.08.11.50.14 (version=TLS1 cipher=AES128-SHA bits=128/128); Thu, 08 Jun 2017 11:50:20 -0700 (PDT) From: Michael Rolnik To: qemu-devel@nongnu.org Date: Thu, 8 Jun 2017 21:49:43 +0300 Message-Id: <20170608184944.19406-9-mrolnik@gmail.com> X-Mailer: git-send-email 2.11.0 (Apple Git-81) In-Reply-To: <20170608184944.19406-1-mrolnik@gmail.com> References: <20170608184944.19406-1-mrolnik@gmail.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:400c:c09::241 Subject: [Qemu-devel] [PATCH RFC v19 08/13] target-avr: instruction decoder generator X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Richard Henderson , Michael Rolnik , anichang@protonmail.ch Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP Signed-off-by: Michael Rolnik Message-Id: <1471522070-77598-9-git-send-email-mrolnik@gmail.com> Signed-off-by: Richard Henderson --- target/avr/cpugen/CMakeLists.txt | 38 +++ target/avr/cpugen/README.md | 17 ++ target/avr/cpugen/cpu/avr.yaml | 213 ++++++++++++++ target/avr/cpugen/src/CMakeLists.txt | 62 ++++ target/avr/cpugen/src/cpugen.cpp | 457 +++++++++++++++++++++++++++++ target/avr/cpugen/src/utils.cpp | 26 ++ target/avr/cpugen/src/utils.h | 78 +++++ target/avr/cpugen/xsl/decode.c.xsl | 103 +++++++ target/avr/cpugen/xsl/translate-inst.h.xsl | 118 ++++++++ target/avr/cpugen/xsl/utils.xsl | 108 +++++++ 10 files changed, 1220 insertions(+) create mode 100644 target/avr/cpugen/CMakeLists.txt create mode 100644 target/avr/cpugen/README.md create mode 100644 target/avr/cpugen/cpu/avr.yaml create mode 100644 target/avr/cpugen/src/CMakeLists.txt create mode 100644 target/avr/cpugen/src/cpugen.cpp create mode 100644 target/avr/cpugen/src/utils.cpp create mode 100644 target/avr/cpugen/src/utils.h create mode 100644 target/avr/cpugen/xsl/decode.c.xsl create mode 100644 target/avr/cpugen/xsl/translate-inst.h.xsl create mode 100644 target/avr/cpugen/xsl/utils.xsl diff --git a/target/avr/cpugen/CMakeLists.txt b/target/avr/cpugen/CMakeLists.txt new file mode 100644 index 0000000000..ded391c9c2 --- /dev/null +++ b/target/avr/cpugen/CMakeLists.txt @@ -0,0 +1,38 @@ +cmake_minimum_required(VERSION 2.8) + +project(cpugen) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -ggdb -g3") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") + +set(Boost_USE_STATIC_LIBS ON) +find_package( + Boost 1.60.0 + REQUIRED + COMPONENTS + system + regex) +#set(BUILD_SHARED_LIBS OFF) +#set(BUILD_STATIC_LIBS ON) +add_subdirectory(tinyxml2) +add_subdirectory(yaml-cpp) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/.. + ${CMAKE_CURRENT_SOURCE_DIR}/../yaml-cpp/include + ${Boost_INCLUDE_DIRS} +) + +add_executable( + cpugen + src/cpugen.cpp + src/utils.cpp +) + +target_link_libraries( + cpugen + yaml-cpp + tinyxml2 + ${Boost_LIBRARIES} +) diff --git a/target/avr/cpugen/README.md b/target/avr/cpugen/README.md new file mode 100644 index 0000000000..f0caa8b135 --- /dev/null +++ b/target/avr/cpugen/README.md @@ -0,0 +1,17 @@ +# CPUGEN +## How to build +within ```cpugen``` directory do +``` +git clone https://github.com/leethomason/tinyxml2 +git clone https://github.com/jbeder/yaml-cpp +mkdir build +cd build +cmake .. +make +``` +## How to use +``` +cpugen ../cpu/avr.yaml +xsltproc ../xsl/decode.c.xsl output.xml > ../../decode.c +xsltproc ../xsl/translate-inst.h.xsl output.xml > ../../translate-inst.h +``` diff --git a/target/avr/cpugen/cpu/avr.yaml b/target/avr/cpugen/cpu/avr.yaml new file mode 100644 index 0000000000..c36b628cf1 --- /dev/null +++ b/target/avr/cpugen/cpu/avr.yaml @@ -0,0 +1,213 @@ +cpu: + name: avr + instructions: + - ADC: + opcode: 0001 11 hRr[1] Rd[5] lRr[4] + - ADD: + opcode: 0000 11 hRr[1] Rd[5] lRr[4] + - ADIW: + opcode: 1001 0110 hImm[2] Rd[2] lImm[4] + - AND: + opcode: 0010 00 hRr[1] Rd[5] lRr[4] + - ANDI: + opcode: 0111 hImm[4] Rd[4] lImm[4] + - ASR: + opcode: 1001 010 Rd[5] 0101 + - BCLR: + opcode: 1001 0100 1 Bit[3] 1000 + - BLD: + opcode: 1111 100 Rd[5] 0 Bit[3] + - BRBC: + opcode: 1111 01 Imm[7] Bit[3] + - BRBS: + opcode: 1111 00 Imm[7] Bit[3] + - BREAK: + opcode: 1001 0101 1001 1000 + - BSET: + opcode: 1001 0100 0 Bit[3] 1000 + - BST: + opcode: 1111 101 Rd[5] 0 Bit[3] + - CALL: + opcode: 1001 010 hImm[5] 111 lImm[17] + - CBI: + opcode: 1001 1000 Imm[5] Bit[3] + - COM: + opcode: 1001 010 Rd[5] 0000 + - CP: + opcode: 0001 01 hRr[1] Rd[5] lRr[4] + - CPC: + opcode: 0000 01 hRr[1] Rd[5] lRr[4] + - CPI: + opcode: 0011 hImm[4] Rd[4] lImm[4] + - CPSE: + opcode: 0001 00 hRr[1] Rd[5] lRr[4] + - DEC: + opcode: 1001 010 Rd[5] 1010 + - DES: + opcode: 1001 0100 Imm[4] 1011 + - EICALL: + opcode: 1001 0101 0001 1001 + - EIJMP: + opcode: 1001 0100 0001 1001 + - ELPM1: + opcode: 1001 0101 1101 1000 + - ELPM2: + opcode: 1001 000 Rd[5] 0110 + - ELPMX: + opcode: 1001 000 Rd[5] 0111 + - EOR: + opcode: 0010 01 hRr[1] Rd[5] lRr[4] + - FMUL: + opcode: 0000 0011 0 Rd[3] 1 Rr[3] + - FMULS: + opcode: 0000 0011 1 Rd[3] 0 Rr[3] + - FMULSU: + opcode: 0000 0011 1 Rd[3] 1 Rr[3] + - ICALL: + opcode: 1001 0101 0000 1001 + - IJMP: + opcode: 1001 0100 0000 1001 + - IN: + opcode: 1011 0 hImm[2] Rd[5] lImm[4] + - INC: + opcode: 1001 010 Rd[5] 0011 + - JMP: + opcode: 1001 010 hImm[5] 110 lImm[17] + - LAC: + opcode: 1001 001 Rr[5] 0110 + - LAS: + opcode: 1001 001 Rr[5] 0101 + - LAT: + opcode: 1001 001 Rr[5] 0111 + - LDX1: + opcode: 1001 000 Rd[5] 1100 + - LDX2: + opcode: 1001 000 Rd[5] 1101 + - LDX3: + opcode: 1001 000 Rd[5] 1110 +# - LDY1: +# opcode: 1000 000 Rd[5] 1000 + - LDY2: + opcode: 1001 000 Rd[5] 1001 + - LDY3: + opcode: 1001 000 Rd[5] 1010 + - LDDY: + opcode: 10 hImm[1] 0 mImm[2] 0 Rd[5] 1 lImm[3] +# - LDZ1: +# opcode: 1000 000 Rd[5] 0000 + - LDZ2: + opcode: 1001 000 Rd[5] 0001 + - LDZ3: + opcode: 1001 000 Rd[5] 0010 + - LDDZ: + opcode: 10 hImm[1] 0 mImm[2] 0 Rd[5] 0 lImm[3] + - LDI: + opcode: 1110 hImm[4] Rd[4] lImm[4] + - LDS: + opcode: 1001 000 Rd[5] 0000 Imm[16] +# - LDS16: +# opcode: 1010 0 hImm[3] Rd[4] lImm[4] + - LPM1: + opcode: 1001 0101 1100 1000 + - LPM2: + opcode: 1001 000 Rd[5] 0100 + - LPMX: + opcode: 1001 000 Rd[5] 0101 + - LSR: + opcode: 1001 010 Rd[5] 0110 + - MOV: + opcode: 0010 11 hRr[1] Rd[5] lRr[4] + - MOVW: + opcode: 0000 0001 Rd[4] Rr[4] + - MUL: + opcode: 1001 11 hRr[1] Rd[5] lRr[4] + - MULS: + opcode: 0000 0010 Rd[4] Rr[4] + - MULSU: + opcode: 0000 0011 0 Rd[3] 0 Rr[3] + - NEG: + opcode: 1001 010 Rd[5] 0001 + - NOP: + opcode: 0000 0000 0000 0000 + - OR: + opcode: 0010 10 hRr[1] Rd[5] lRr[4] + - ORI: + opcode: 0110 hImm[4] Rd[4] lImm[4] + - OUT: + opcode: 1011 1 hImm[2] Rd[5] lImm[4] + - POP: + opcode: 1001 000 Rd[5] 1111 + - PUSH: + opcode: 1001 001 Rd[5] 1111 + - RCALL: + opcode: 1101 Imm[12] + - RET: + opcode: 1001 0101 0000 1000 + - RETI: + opcode: 1001 0101 0001 1000 + - RJMP: + opcode: 1100 Imm[12] + - ROR: + opcode: 1001 010 Rd[5] 0111 + - SBC: + opcode: 0000 10 hRr[1] Rd[5] lRr[4] + - SBCI: + opcode: 0100 hImm[4] Rd[4] lImm[4] + - SBI: + opcode: 1001 1010 Imm[5] Bit[3] + - SBIC: + opcode: 1001 1001 Imm[5] Bit[3] + - SBIS: + opcode: 1001 1011 Imm[5] Bit[3] + - SBIW: + opcode: 1001 0111 hImm[2] Rd[2] lImm[4] +# - SBR: +# opcode: 0110 hImm[4] Rd[4] lImm[4] + - SBRC: + opcode: 1111 110 Rr[5] 0 Bit[3] + - SBRS: + opcode: 1111 111 Rr[5] 0 Bit[3] + - SLEEP: + opcode: 1001 0101 1000 1000 + - SPM: + opcode: 1001 0101 1110 1000 + - SPMX: + opcode: 1001 0101 1111 1000 + - STX1: + opcode: 1001 001 Rr[5] 1100 + - STX2: + opcode: 1001 001 Rr[5] 1101 + - STX3: + opcode: 1001 001 Rr[5] 1110 +# - STY1: +# opcode: 1000 001 Rd[5] 1000 + - STY2: + opcode: 1001 001 Rd[5] 1001 + - STY3: + opcode: 1001 001 Rd[5] 1010 + - STDY: + opcode: 10 hImm[1] 0 mImm[2] 1 Rd[5] 1 lImm[3] +# - STZ1: +# opcode: 1000 001 Rd[5] 0000 + - STZ2: + opcode: 1001 001 Rd[5] 0001 + - STZ3: + opcode: 1001 001 Rd[5] 0010 + - STDZ: + opcode: 10 hImm[1] 0 mImm[2] 1 Rd[5] 0 lImm[3] + - STS: + opcode: 1001 001 Rd[5] 0000 Imm[16] +# - STS16: +# opcode: 1010 1 hImm[3] Rd[4] lImm[4] + - SUB: + opcode: 0001 10 hRr[1] Rd[5] lRr[4] + - SUBI: + opcode: 0101 hImm[4] Rd[4] lImm[4] + - SWAP: + opcode: 1001 010 Rd[5] 0010 +# - TST: +# opcode: 0010 00 Rd[10] + - WDR: + opcode: 1001 0101 1010 1000 + - XCH: + opcode: 1001 001 Rd[5] 0100 diff --git a/target/avr/cpugen/src/CMakeLists.txt b/target/avr/cpugen/src/CMakeLists.txt new file mode 100644 index 0000000000..5f08761dbf --- /dev/null +++ b/target/avr/cpugen/src/CMakeLists.txt @@ -0,0 +1,62 @@ +# +# CPUGEN +# +# Copyright (c) 2016 Michael Rolnik +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + +cmake_minimum_required(VERSION 2.8) + +project(cpugen) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -ggdb -g3") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") + +set(Boost_USE_STATIC_LIBS ON) +find_package( + Boost 1.60.0 + REQUIRED + COMPONENTS + system + regex) +set(BUILD_SHARED_LIBS OFF) +set(BUILD_STATIC_LIBS ON) +add_subdirectory(../tinyxml2 ${CMAKE_CURRENT_BINARY_DIR}/tinyxml2) +add_subdirectory(../yaml-cpp ${CMAKE_CURRENT_BINARY_DIR}/yaml-cpp) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/.. + ${CMAKE_CURRENT_SOURCE_DIR}/../yaml-cpp/include + ${Boost_INCLUDE_DIRS} +) + +add_executable( + cpugen + cpugen.cpp + utils.cpp +) + +target_link_libraries( + cpugen + yaml-cpp + tinyxml2_static + ${Boost_LIBRARIES} +) diff --git a/target/avr/cpugen/src/cpugen.cpp b/target/avr/cpugen/src/cpugen.cpp new file mode 100644 index 0000000000..e479b08251 --- /dev/null +++ b/target/avr/cpugen/src/cpugen.cpp @@ -0,0 +1,457 @@ +/* + * CPUGEN + * + * Copyright (c) 2016 Michael Rolnik + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "yaml-cpp/yaml.h" +#include "tinyxml2/tinyxml2.h" + +#include "utils.h" + +#include + +struct inst_info_t { + std::string name; + std::string opcode; + + tinyxml2::XMLElement *nodeFields; +}; + +struct cpu_info_t { + std::string name; + std::vector instructions; +}; + +int countbits(uint64_t value) +{ + int counter = 0; + uint64_t mask = 1; + + for (size_t i = 0; i < sizeof(value) * 8; ++i) { + if (value & mask) { + counter++; + } + + mask <<= 1; + } + + return counter; +} + +int encode(uint64_t mask, uint64_t value) +{ + uint64_t i = 0x0000000000000001; + uint64_t j = 0x0000000000000001; + uint64_t v = 0x0000000000000000; + + for (size_t it = 0; it < sizeof(value) * 8; ++it) { + if (mask & i) { + if (value & j) { + v |= i; + } + j <<= 1; + } + + i <<= 1; + } + + return v; +} + +std::string num2hex(uint64_t value) +{ + std::ostringstream str; + str << "0x" << std::hex << std::setw(8) << std::setfill('0') << value; + + return str.str(); +} + +tinyxml2::XMLDocument doc; + +void operator >> (const YAML::Node & node, inst_info_t & info) +{ + for (auto it = node.begin(); it != node.end(); ++it) { + const YAML::Node & curr = it->second; + std::string name = it->first.as(); + + info.opcode = curr["opcode"].as(); + + const char *response; + std::vector fields; + std::string opcode = ""; + int offset; + tinyxml2::XMLElement *nodeFields = doc.NewElement("fields"); + uint32_t bitoffset = 0; + + do { + opcode = info.opcode; + boost::replace_all(info.opcode, " ", " "); + boost::replace_all(info.opcode, "0 0", "00"); + boost::replace_all(info.opcode, "0 1", "01"); + boost::replace_all(info.opcode, "1 0", "10"); + boost::replace_all(info.opcode, "1 1", "11"); + } while (opcode != info.opcode); + + boost::replace_all(info.opcode, "- -", "--"); + + fields = boost::split(fields, info.opcode, boost::is_any_of(" ")); + + opcode = ""; + info.opcode = ""; + unsigned f = 0; + for (int i = 0; i < fields.size(); i++) { + std::string field = fields[i]; + + if (field.empty()) { + continue; + } + + size_t len = field.length(); + boost::cmatch match; + tinyxml2::XMLElement *nodeField = doc.NewElement("field"); + + nodeFields->LinkEndChild(nodeField); + + if (boost::regex_match(field.c_str(), + match, + boost::regex("^[01]+$"))) { + int length = field.length(); + + nodeField->SetAttribute("name", field.c_str()); + nodeField->SetAttribute("length", length); + nodeField->SetAttribute("offset", bitoffset); + + info.opcode += field; + + bitoffset += len; + } else if (boost::regex_match( + field.c_str(), + match, + boost::regex("^[-]+$"))) + { + int length = field.length(); + + nodeField->SetAttribute("name", "RESERVED"); + nodeField->SetAttribute("length", length); + nodeField->SetAttribute("offset", bitoffset); + + info.opcode += field; + + bitoffset += len; + } else if (boost::regex_match(field.c_str(), + match, + boost::regex("^([a-zA-Z][a-zA-Z0-9]*)\\[([0-9]+)\\]"))) { + int length = std::atoi(match[2].first); + std::string name = std::string(match[1].first, match[1].second); + + nodeField->SetAttribute("name", name.c_str()); + nodeField->SetAttribute("length", length); + nodeField->SetAttribute("offset", bitoffset); + + for (int j = 0; j < length; j++) { + info.opcode += 'a' + f; + } + + f++; + + bitoffset += length; + } else if (field == "~") { + /* nothing */ + } else { + std::cout << "cannot parse " << name + << ": '" << field << "'" << std::endl; + exit(0); + } + } + + info.nodeFields = nodeFields; + info.name = name; + } +} + +void operator >> (inst_info_t & info, tinyxml2::XMLElement & node) +{ + node.SetAttribute("length", (unsigned)info.opcode.length()); + node.SetAttribute("name", info.name.c_str()); + node.SetAttribute("opcode", info.opcode.c_str()); +} + +void operator >> (const YAML::Node & node, cpu_info_t & cpu) +{ + const YAML::Node & insts = node["instructions"]; + + cpu.name = node["name"].as(); + + for (unsigned i = 0; i < insts.size(); i++) { + inst_info_t *inst = new inst_info_t(); + + insts[i] >> (*inst); + + if (inst->opcode != "" &&inst->opcode != "~") { + cpu.instructions.push_back(inst); + } + } +} + +std::pair getMinMaxInstructionLength( + std::vector &instructions) +{ + size_t min = std::numeric_limits::max(); + size_t max = std::numeric_limits::min(); + + for (size_t i = 0; i < instructions.size(); i++) { + inst_info_t *inst = instructions[i]; + std::string opcode = inst->opcode; + size_t length = opcode.length(); + + if (opcode != "~") { + min = std::min(min, length); + max = std::max(max, length); + } + } + + return std::make_pair(min, max); +} + +uint64_t getXs(std::string const &opcode, size_t len, char chr) +{ + uint64_t result = 0; + size_t cur; + uint64_t bit = 1ull << (len - 1); + + for (cur = 0; cur < len; cur++) { + if (opcode[cur] == chr) { + result |= bit; + } + + bit >>= 1; + } + + return result; +} + +uint64_t get0s(std::string const &opcode, size_t len) +{ + return getXs(opcode, len, '0'); +} + +uint64_t get1s(std::string const &opcode, size_t len) +{ + return getXs(opcode, len, '1'); +} + +class InstSorter +{ + public: + InstSorter(size_t offset, size_t length) + : offset(offset), length(length) + { + + } + + bool operator()(inst_info_t *a, inst_info_t *b) + { + uint64_t field0; + uint64_t field1; + uint64_t fieldA; + uint64_t fieldB; + + field0 = get0s(a->opcode, length); + field1 = get1s(a->opcode, length); + fieldA = field0 | field1; + + field0 = get0s(b->opcode, length); + field1 = get1s(b->opcode, length); + fieldB = field0 | field1; + + return fieldB < fieldA; + } + + private: + size_t offset; + size_t length; + +}; + +void divide(uint64_t select0, uint64_t select1, + std::vector &info, + size_t level, tinyxml2::XMLElement *root) +{ + std::pair minmaxSize; + + minmaxSize = getMinMaxInstructionLength(info); + + size_t minlen = minmaxSize.first; + size_t maxlen = minmaxSize.second; + size_t bits = std::min(minlen, sizeof(select0) * 8); + uint64_t all1 = (1ULL << bits) - 1; + uint64_t all0 = (1ULL << bits) - 1; + uint64_t allx = (1ULL << bits) - 1; + uint64_t diff; + + for (size_t i = 0; i < info.size(); ++i) { + std::string opcode = info[i]->opcode; + uint64_t field0 = get0s(opcode, minlen); + uint64_t field1 = get1s(opcode, minlen); + uint64_t fieldx = field0 | field1; + + if (opcode == "~") { + continue; + } + all0 &= field0; + all1 &= field1; + allx &= fieldx; + } + + diff = allx ^ (all0 | all1); + + if (diff == 0) { + tinyxml2::XMLElement *oopsNode = doc.NewElement("oops"); + oopsNode->SetAttribute("bits", (unsigned)bits); + oopsNode->SetAttribute("maxlen", (unsigned)maxlen); + oopsNode->SetAttribute("allx", num2hex(allx).c_str()); + oopsNode->SetAttribute("all0", num2hex(all0).c_str()); + oopsNode->SetAttribute("all1", num2hex(all1).c_str()); + oopsNode->SetAttribute("select0", num2hex(select0).c_str()); + oopsNode->SetAttribute("select1", num2hex(select1).c_str()); + root->LinkEndChild(oopsNode); + + std::sort(info.begin(), info.end(), InstSorter(0, minlen)); + + for (size_t i = 0; i < info.size(); ++i) { + inst_info_t *inst = info[i]; + tinyxml2::XMLElement *instNode = doc.NewElement("instruction"); + tinyxml2::XMLElement *matchNode = doc.NewElement("match01"); + + uint64_t field0 = get0s(inst->opcode, minlen); + uint64_t field1 = get1s(inst->opcode, minlen); + uint64_t fieldx = field0 | field1; + + root->LinkEndChild(matchNode); + matchNode->LinkEndChild(instNode); + + matchNode->SetAttribute("mask", num2hex(fieldx).c_str()); + matchNode->SetAttribute("value", num2hex(field1).c_str()); + + *inst >> *instNode; + + instNode->LinkEndChild(inst->nodeFields); + } + + return; + } + + uint64_t bitsN = countbits(diff); /* number of meaningfull bits */ + + tinyxml2::XMLElement *switchNode = doc.NewElement("switch"); + switchNode->SetAttribute("bits", (unsigned)bits); + switchNode->SetAttribute("bitoffset", (unsigned)0); + switchNode->SetAttribute("mask", num2hex(diff).c_str()); + root->LinkEndChild(switchNode); + + /* there are at most 1 << length subsets */ + for (size_t s = 0; s < (1 << bitsN); ++s) { + std::vector subset; + uint64_t index = encode(diff, s); + + tinyxml2::XMLElement *caseNode = doc.NewElement("case"); + caseNode->SetAttribute("value", num2hex(index).c_str()); + switchNode->LinkEndChild(caseNode); + + for (size_t i = 0; i < info.size(); ++i) { + std::string opcode = info[i]->opcode; + uint64_t field0 = get0s(opcode, minlen); + uint64_t field1 = get1s(opcode, minlen); + + if (((field0 & diff) == (~index & diff)) + && ((field1 & diff) == (index & diff))) { + subset.push_back(info[i]); + } + } + + if (subset.size() == 1) { + inst_info_t *inst = subset[0]; + tinyxml2::XMLElement *instNode = doc.NewElement("instruction"); + + *inst >> *instNode; + + instNode->LinkEndChild(inst->nodeFields); + + caseNode->LinkEndChild(instNode); + } else if (subset.size() > 1) { + /* this is a set of instructions, continue dividing */ + divide(select0 | (diff & ~index), + select1 | (diff & index), + subset, + level + 2, + caseNode); + } + } +} + +void generateParser(cpu_info_t & cpu) +{ + tinyxml2::XMLElement *cpuNode = doc.NewElement("cpu"); + tinyxml2::XMLElement *instNode = doc.NewElement("instructions"); + + cpuNode->SetAttribute("name", cpu.name.c_str()); + cpuNode->LinkEndChild(instNode); + + doc.LinkEndChild(cpuNode); + + divide(0, 0, cpu.instructions, 1, instNode); + + doc.SaveFile("output.xml"); +} + +int main(int argc, char *argv[]) +{ + if (argc != 2) { + std::cerr << "error: usage: cpuarg [input.yaml]" << std::endl; + std::exit(0); + } + + try { + const char *filename = argv[1]; + std::ifstream input(filename); + YAML::Node doc = YAML::Load(input); + cpu_info_t cpu; + + doc["cpu"] >> cpu; + + generateParser(cpu); + } catch(const YAML::Exception & e) { + std::cerr << e.what() << "\n"; + } +} diff --git a/target/avr/cpugen/src/utils.cpp b/target/avr/cpugen/src/utils.cpp new file mode 100644 index 0000000000..5ef1961418 --- /dev/null +++ b/target/avr/cpugen/src/utils.cpp @@ -0,0 +1,26 @@ +/* + * CPUGEN + * + * Copyright (c) 2016 Michael Rolnik + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "utils.h" +#include diff --git a/target/avr/cpugen/src/utils.h b/target/avr/cpugen/src/utils.h new file mode 100644 index 0000000000..0efaa3eded --- /dev/null +++ b/target/avr/cpugen/src/utils.h @@ -0,0 +1,78 @@ +/* + * CPUGEN + * + * Copyright (c) 2016 Michael Rolnik + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef UTILS_H_ +#define UTILS_H_ + +#include +#include +#include +#include + +typedef std::vector string_vector_t; + +std::string extract(std::string & str, std::string delimiter); +std::string rextract(std::string & str, std::string del); +string_vector_t split(std::string str, std::string delimeter); +std::string join(string_vector_t const &vec, std::string delimeter); + +int countbits(uint64_t value); +int encode(uint64_t mask, uint64_t value); +std::string num2hex(uint64_t value); + +class multi +{ +/* + http://www.angelikalanger.com/Articles/Cuj/05.Manipulators/Manipulators.html +*/ + public: + multi(char c, size_t n) + : how_many_(n) + , what_(c) + { + } + + private: + const size_t how_many_; + const char what_; + + public: + template + Ostream & apply(Ostream & os) const + { + for (unsigned int i = 0; i < how_many_; ++i) { + os.put(what_); + } + os.flush(); + return os; + } +}; + +template +Ostream & operator << (Ostream & os, const multi & m) +{ + return m.apply(os); +} + +#endif diff --git a/target/avr/cpugen/xsl/decode.c.xsl b/target/avr/cpugen/xsl/decode.c.xsl new file mode 100644 index 0000000000..b8aa02c5d7 --- /dev/null +++ b/target/avr/cpugen/xsl/decode.c.xsl @@ -0,0 +1,103 @@ + + + + + + + + + + + + + +#include <stdint.h> +#include "translate.h" + +void _decode(uint32_t pc, uint32_t *l, uint32_t c, translate_function_t *t) +{ + + + + + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/target/avr/cpugen/xsl/translate-inst.h.xsl b/target/avr/cpugen/xsl/translate-inst.h.xsl new file mode 100644 index 0000000000..2830ce3d1b --- /dev/null +++ b/target/avr/cpugen/xsl/translate-inst.h.xsl @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + +#ifndef AVR_TRANSLATE_INST_H_ +#define AVR_TRANSLATE_INST_H_ + +typedef struct DisasContext DisasContext; + + + + + + +#endif + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/target/avr/cpugen/xsl/utils.xsl b/target/avr/cpugen/xsl/utils.xsl new file mode 100644 index 0000000000..b4511b6438 --- /dev/null +++ b/target/avr/cpugen/xsl/utils.xsl @@ -0,0 +1,108 @@ + + + + + + + + + + + + + /* + * QEMU AVR CPU + * + * Copyright (c) 2016 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 + * <http://www.gnu.org/licenses/lgpl-2.1.html> + */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +