From patchwork Wed Jun 22 09:51:55 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Rolnik X-Patchwork-Id: 9192323 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 F0D3B60756 for ; Wed, 22 Jun 2016 10:03:58 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DC92B1FFB9 for ; Wed, 22 Jun 2016 10:03:58 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D0C45283DF; Wed, 22 Jun 2016 10:03:58 +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 2F8EF1FFB9 for ; Wed, 22 Jun 2016 10:03:56 +0000 (UTC) Received: from localhost ([::1]:56897 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bFf0l-0005PG-6B for patchwork-qemu-devel@patchwork.kernel.org; Wed, 22 Jun 2016 06:03:55 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:40750) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bFepq-0002b2-Ok for qemu-devel@nongnu.org; Wed, 22 Jun 2016 05:52:43 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bFepl-0006Kq-Ck for qemu-devel@nongnu.org; Wed, 22 Jun 2016 05:52:37 -0400 Received: from mail-lb0-x242.google.com ([2a00:1450:4010:c04::242]:36559) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bFepk-0006KS-MD for qemu-devel@nongnu.org; Wed, 22 Jun 2016 05:52:33 -0400 Received: by mail-lb0-x242.google.com with SMTP id ur4so3818959lbc.3 for ; Wed, 22 Jun 2016 02:52:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=ma6zn4mqLwL1iGbChVlv2+9h9271MdePJLZFSAO7+Bc=; b=amhU6lnYME60/jKg4Isk5Zm1OiUTC0HLlIlqknAa8mqOG1jC7Q0PagMc3lVHPhYM6D ok/swGqHXJi3jhsZbbJ0f+Z+GcOxI5EwkZLs6L2tzZNNiu/BKdRXP9HCfLdNZFAHcYb+ Pej0YXTi/XZ6uanNu0aYVIQESBezW60OeX3Hdx0e3ZGik2l0IvPKRinCi+3uoJqCShdl tPLqZS7mb4iwmwpuCZ56QfotVMql27DAY3RABHFgIetI9yGLhUT8HapUTs088/h199l6 Cc18p5VPAdeN7b1jHn+SwOiXyY0uXHep86kQH8Po9R/TQClL5OG7qgZx7mq3E1wplq8J 78zA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=ma6zn4mqLwL1iGbChVlv2+9h9271MdePJLZFSAO7+Bc=; b=EOtEgocOWKhiVXuaKAaSPvAPEfEsyr1hUItCgYHLTBlE5H76gDzAabW1XpFzoxn7VB OuE1bEe+jdhr8BzoZ62ven+bwqkIdatjoVbHrhJLxDMXMVT7x8OD9Z+E2LWOVCpZLCVn CDYjCiOuKpKS2DvmI/ufkVBRUxe3or2nQFha0xrJci8p0BefaT9Pg9P2WKWHQETBmMcN 1t3g9JHoTBO3G/wI0prFaZYuY16W8aBc+m/xbLzjKGqNnud6oxadqA1LMIjsiKiY+Hlv wFca59CUhgvT4MvTQut/lsZz212awdwrrqJ47baPN7wDu1cF5cwyARdyCn773FzFvLF/ Ttig== X-Gm-Message-State: ALyK8tLXflMytn7EJ1SgPGyDndYvxLQBhAWFzsZ6wA/+MiP6fxeiIRFjPjslAx9TFLobOw== X-Received: by 10.194.145.244 with SMTP id sx20mr26098189wjb.169.1466589151220; Wed, 22 Jun 2016 02:52:31 -0700 (PDT) Received: from a0999b0126e1.ant.amazon.com ([5.102.195.79]) by smtp.gmail.com with ESMTPSA id b187sm7215976wmg.15.2016.06.22.02.52.29 (version=TLS1 cipher=AES128-SHA bits=128/128); Wed, 22 Jun 2016 02:52:29 -0700 (PDT) From: Michael Rolnik To: qemu-devel@nongnu.org Date: Wed, 22 Jun 2016 12:51:55 +0300 Message-Id: <1466589115-57738-11-git-send-email-mrolnik@gmail.com> X-Mailer: git-send-email 2.4.9 (Apple Git-60) In-Reply-To: <1466589115-57738-1-git-send-email-mrolnik@gmail.com> References: <1466589115-57738-1-git-send-email-mrolnik@gmail.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2a00:1450:4010:c04::242 Subject: [Qemu-devel] [PATCH v9 10/10] target-avr: decoder generator. currently not used by the build, can be used manually 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: peter.maydell@linaro.org, Michael Rolnik , rth@twiddle.net 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 --- target-avr/cpugen/CMakeLists.txt | 38 +++ target-avr/cpugen/README.md | 17 ++ target-avr/cpugen/cpu/avr.yaml | 214 ++++++++++++++ target-avr/cpugen/src/CMakeLists.txt | 62 ++++ target-avr/cpugen/src/cpugen.cpp | 460 +++++++++++++++++++++++++++++ target-avr/cpugen/src/utils.cpp | 27 ++ target-avr/cpugen/src/utils.h | 79 +++++ 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, 1226 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 0000000..ded391c --- /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 0000000..f0caa8b --- /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 0000000..a626859 --- /dev/null +++ b/target-avr/cpugen/cpu/avr.yaml @@ -0,0 +1,214 @@ +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 0000000..5f08761 --- /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 0000000..912dc55 --- /dev/null +++ b/target-avr/cpugen/src/cpugen.cpp @@ -0,0 +1,460 @@ +/* + * 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 { + char const *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 0000000..2261139 --- /dev/null +++ b/target-avr/cpugen/src/utils.cpp @@ -0,0 +1,27 @@ +/* + * 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 0000000..0d96b7e --- /dev/null +++ b/target-avr/cpugen/src/utils.h @@ -0,0 +1,79 @@ +/* + * 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 0000000..b8aa02c --- /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 0000000..2830ce3 --- /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 0000000..b4511b6 --- /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> + */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +