From: Michael Rolnik <rol...@amazon.com> --- target-avr/cpugen/CMakeLists.txt | 38 +++ target-avr/cpugen/README.md | 17 + target-avr/cpugen/cpu/avr.yaml | 218 ++++++++++++ target-avr/cpugen/src/CMakeLists.txt | 62 ++++ target-avr/cpugen/src/cpugen.cpp | 510 +++++++++++++++++++++++++++++ target-avr/cpugen/src/utils.cpp | 27 ++ target-avr/cpugen/src/utils.h | 84 +++++ 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, 1285 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..eb7b754 --- /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..dfa7d32 --- /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..adf209a --- /dev/null +++ b/target-avr/cpugen/cpu/avr.yaml @@ -0,0 +1,218 @@ +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..38f1125 --- /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..fb2489d --- /dev/null +++ b/target-avr/cpugen/src/cpugen.cpp @@ -0,0 +1,510 @@ +/* + * 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 <cstdio> +#include <cstdlib> +#include <iostream> +#include <fstream> +#include <limits> +#include <stdint.h> +#include <algorithm> +#include <iomanip> +#include <string> +#include <vector> +#include <boost/regex.hpp> + +#include "yaml-cpp/yaml.h" +#include "tinyxml2/tinyxml2.h" + +#include "utils.h" + +#include <boost/algorithm/string.hpp> + +struct inst_info_t +{ + std::string name; + std::string opcode; + + tinyxml2::XMLElement* nodeFields; +}; + +struct cpu_info_t +{ + std::string name; + std::vector<inst_info_t*> 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') << std::right << 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<std::string>(); + + info.opcode = curr["opcode"].as<std::string>(); + + const char* response; + std::vector<std::string> 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 == "~") + { + } + 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<std::string>(); + + 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<size_t, size_t> getMinMaxInstructionLength(std::vector<inst_info_t*>& instructions) +{ + size_t min = std::numeric_limits<size_t>::max(); + size_t max = std::numeric_limits<size_t>::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 beg, + size_t end, + char chr) +{ + uint64_t result = 0; + size_t cur; + uint64_t bit = 1ull << (end - 1); + + for(cur = beg; cur < end; cur++) + { + if(opcode[cur] == chr) + result |= bit; + + bit >>= 1; + } + + return result; +} + +uint64_t get0s( std::string const & opcode, + size_t beg, + size_t end) +{ + return getXs(opcode, beg, end, '0'); +} + +uint64_t get1s( std::string const& opcode, + size_t beg, + size_t end) +{ + return getXs(opcode, beg, end, '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, offset, offset + length); + field1 = get1s(a->opcode, offset, offset + length); + fieldA = field0 | field1; + + field0 = get0s(b->opcode, offset, offset + length); + field1 = get1s(b->opcode, offset, offset + length); + fieldB = field0 | field1; + + return fieldB < fieldA; + } + + private: + size_t offset; + size_t length; + +}; + +void divide( size_t begbit, // first bit to look at + uint64_t select0, // these two params + uint64_t select1, // differentiate this set of instuction from all the others + std::vector<inst_info_t*>& info, + size_t level, + tinyxml2::XMLElement* root) +{ + std::pair<size_t, size_t> minmaxSize; + begbit = 0; + + minmaxSize = getMinMaxInstructionLength(info); + + size_t minlen = minmaxSize.first; + size_t maxlen = minmaxSize.second; + size_t bits = std::min(minlen - begbit, sizeof(select0) * 8); + uint64_t all1 = (1ULL << bits) - 1; // mask of bits that are 0 for all instructions + uint64_t all0 = (1ULL << bits) - 1; // mask of bits that are 1 for all instructions + uint64_t allx = (1ULL << bits) - 1; // mask of bits that are either 0 or 1 + uint64_t diff; + + for(size_t i = 0; i < info.size(); ++i) + { + std::string opcode = info[i]->opcode; + uint64_t field0 = get0s(opcode, begbit, minlen); + uint64_t field1 = get1s(opcode, begbit, minlen); + uint64_t fieldx = field0 | field1; + + if(opcode == "~") + continue; + all0 &= field0; + all1 &= field1; + allx &= fieldx; + } + + diff = allx + ^ (all0 | all1); + + if(diff == 0) + { +#if 0 + if( (bits + begbit <= maxlen) + && (bits != 0) + && (begbit != 0)) + { + divide(begbit + bits, 0, 0, info, level, root); + } + else +#endif + { + tinyxml2::XMLElement* oopsNode= doc.NewElement("oops"); + oopsNode->SetAttribute("bits", (unsigned)bits); + oopsNode->SetAttribute("begbit", (unsigned)begbit); + 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(begbit, minlen - begbit)); + + 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, begbit, minlen); + uint64_t field1 = get1s(inst->opcode, begbit, 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)begbit); + switchNode->SetAttribute("mask", num2hex(diff).c_str()); + root->LinkEndChild(switchNode); + + for(size_t s = 0; s < (1 << bitsN); ++s) // there are at most 1 << length subsets + { + std::vector<inst_info_t*> 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, begbit, minlen); + uint64_t field1 = get1s(opcode, begbit, 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( begbit, + 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, 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..2f90dfa --- /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 <sstream> + diff --git a/target-avr/cpugen/src/utils.h b/target-avr/cpugen/src/utils.h new file mode 100644 index 0000000..8f76cbf --- /dev/null +++ b/target-avr/cpugen/src/utils.h @@ -0,0 +1,84 @@ +/* + * 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 <string> +#include <vector> +#include <iostream> +#include <iomanip> + +typedef std::vector<std::string> string_vector_t; + +std::string extract(std::string& str, + std::string delimiter); +std::string rextract( + std::string& str, // + std::string del); // delimiter +string_vector_t split( std::string str, // string to be splitted + std::string delimeter); // delimiter +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 +{ + // src - 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 <class Ostream> + Ostream& apply(Ostream& os) const + { + for(unsigned int i = 0; i < how_many_; ++i) + os.put(what_); + os.flush(); + return os; + } +}; + +template <class Ostream> +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..e5c0396 --- /dev/null +++ b/target-avr/cpugen/xsl/decode.c.xsl @@ -0,0 +1,103 @@ +<?xml version="1.0"?> +<!-- + 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. +--> + +<xsl:stylesheet version="1.0" + xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" + xmlns:func = "http://exslt.org/functions" + xmlns:str = "http://exslt.org/strings" + xmlns:mine = "mrol...@gmail.com" + extension-element-prefixes="func" + > + + <xsl:strip-space elements="*"/> + <xsl:output method="text" omit-xml-declaration="yes" indent="yes"/> + + <xsl:include href="utils.xsl"/> + + <xsl:template match="/cpu/instructions"> + <xsl:value-of select="$license" /> + <xsl:text> +#include <stdint.h> +#include "translate.h" + +void </xsl:text><xsl:value-of select="/cpu/@name"/><xsl:text>_decode(uint32_t pc, uint32_t *l, uint32_t c, translate_function_t *t) +{ +</xsl:text> + <xsl:apply-templates select="switch"> + <xsl:with-param name="ident" ><xsl:value-of select="$tab"/></xsl:with-param> + </xsl:apply-templates> +<xsl:text> +} +</xsl:text> +</xsl:template> + + <xsl:template match="switch"> + <xsl:param name="ident" /> + <xsl:if test="not (@bitoffset = ../../@bitoffset and @bits = ../../@bits)" > + <xsl:value-of select="concat($ident, 'uint32_t opc = extract32(c, ', @bitoffset, ', ', @bits, ');', $newline)" /> + </xsl:if> + <xsl:value-of select="concat($ident, 'switch (opc & ', @mask, ') {', $newline)"/> + <xsl:apply-templates select="case"> + <xsl:with-param name="ident" ><xsl:value-of select="$ident"/><xsl:value-of select="$tab"/></xsl:with-param> + </xsl:apply-templates> + <xsl:value-of select="concat($ident, '}', $newline)"/> + </xsl:template> + + <xsl:template match="case"> + <xsl:param name="ident" /> + + <xsl:value-of select="concat($ident, 'case ', @value, ': {', $newline)"/> + <xsl:apply-templates select="switch"> + <xsl:with-param name="ident"><xsl:value-of select="concat($ident, $tab)"/></xsl:with-param> + </xsl:apply-templates> + <xsl:apply-templates select="match01"> + <xsl:with-param name="ident"><xsl:value-of select="concat($ident, $tab)"/></xsl:with-param> + </xsl:apply-templates> + <xsl:apply-templates select="instruction"> + <xsl:with-param name="ident"><xsl:value-of select="concat($ident, $tab)"/></xsl:with-param> + </xsl:apply-templates> + <xsl:value-of select="concat($ident, $tab, 'break;', $newline)"/> + <xsl:value-of select="concat($ident, '}', $newline)"/> + </xsl:template> + + <xsl:template match="instruction"> + <xsl:param name="ident" /> + + <xsl:value-of select="concat($ident, '*l = ', string-length(@opcode), ';', $newline)" /> + <xsl:value-of select="concat($ident, '*t = &', /cpu/@name, '_translate_', @name, ';', $newline)" /> + </xsl:template> + + <xsl:template match="match01"> + <xsl:param name="ident" /> + + <xsl:value-of select="concat($ident, 'if((opc & ', @mask, ' == ', @value, ') {', $newline)" /> + <xsl:apply-templates select="instruction"> + <xsl:with-param name="ident"><xsl:value-of select="concat($ident, $tab)"/></xsl:with-param> + </xsl:apply-templates> + <xsl:value-of select="concat($ident, 'break;', $newline)"/> + <xsl:value-of select="concat($ident, '}', $newline)"/> + </xsl:template> + +</xsl:stylesheet> 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..4ed02b3 --- /dev/null +++ b/target-avr/cpugen/xsl/translate-inst.h.xsl @@ -0,0 +1,118 @@ +<?xml version="1.0"?> + +<!-- + 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. +--> + +<xsl:stylesheet version="1.0" + xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" + xmlns:func = "http://exslt.org/functions" + xmlns:str = "http://exslt.org/strings" + xmlns:mine = "mrol...@gmail.com" + extension-element-prefixes="func" + > + + <xsl:include href="utils.xsl"/> + +<xsl:strip-space elements="*"/> +<xsl:output method="text" omit-xml-declaration="yes" indent="yes"/> + +<xsl:template match="/cpu/instructions"> + <xsl:value-of select="$license" /> +<xsl:text> +#ifndef AVR_TRANSLATE_INST_H_ +#define AVR_TRANSLATE_INST_H_ + +typedef struct DisasContext DisasContext; + +</xsl:text> + +<xsl:apply-templates select="//instruction" /> + +<xsl:text> +#endif +</xsl:text> +</xsl:template> + +<xsl:template match="instruction"> + <xsl:variable name="length" select="string-length(@opcode)" /> + <xsl:variable name="datatype" select="mine:get-opcode-struct-type($length)" /> + <xsl:variable name="namestem" select="@name"/> + <xsl:variable name="ilength" select="@length"/> + + <xsl:value-of select="concat('int ', /cpu/@name, '_translate_', @name, '(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);', $newline)" /> + <xsl:for-each select="fields/field"> + <xsl:sort select="position()" data-type="number" order="descending"/> + <xsl:choose> + <xsl:when test="str:replace(str:replace(@name, '0', ''), '1', '') = ''"> + </xsl:when> + <xsl:otherwise> + <xsl:variable name="field" select="substring(@name, 2, string-length(@name) - 1)" /> + <xsl:variable name="h" select="../field[@name = concat('h', $field)]"/> + <xsl:variable name="l" select="../field[@name = concat('l', $field)]"/> + <xsl:variable name="m" select="../field[@name = concat('m', $field)]"/> + + <xsl:if test="not($h/@name = @name or $m/@name = @name or $l/@name = @name)"> + <xsl:value-of select="concat('static inline uint32_t ', $namestem, '_', @name, '(uint32_t opcode)', $newline)" /> + <xsl:value-of select="concat('{', $newline)" /> + <xsl:value-of select="concat(' return extract32(opcode, ', $ilength - @offset - @length, ', ', @length, ');', $newline)" /> + <xsl:value-of select="concat('}', $newline)" /> + </xsl:if> + + <xsl:if test="$l and $h and ($h/@name = @name)"> + <xsl:value-of select="concat('static inline uint32_t ', $namestem, '_', $field, '(uint32_t opcode)', $newline)" /> + <xsl:value-of select="concat('{', $newline)" /> + <xsl:value-of select="' return '" /> + +<xsl:variable name="l_length" select="$l/@length"/> +<xsl:variable name="l_offset" select="$ilength - $l/@offset - $l_length"/> + +<xsl:variable name="m_length" select="$m/@length"/> +<xsl:variable name="m_offset" select="$ilength - $m/@offset - $m_length"/> + +<xsl:variable name="h_length" select="$h/@length"/> +<xsl:variable name="h_offset" select="$ilength - $h/@offset - $h_length"/> + + + <xsl:choose> + <xsl:when test="$h and $m and $l"> + <xsl:value-of select="concat('(extract32(opcode, ', $h_offset, ', ', $h_length, ') << ', $l_length + $m_length, ') | ')" /> + <xsl:value-of select="concat('(extract32(opcode, ', $m_offset, ', ', $m_length, ') << ', $l_length, ') | ')" /> + <xsl:value-of select="concat('(extract32(opcode, ', $l_offset, ', ', $l_length, '))')" /> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="concat('(extract32(opcode, ', $h_offset, ', ', $h_length, ') << ', $l_length, ') | ')" /> + <xsl:value-of select="concat('(extract32(opcode, ', $l_offset, ', ', $l_length, '))')" /> + </xsl:otherwise> + </xsl:choose> + + <xsl:value-of select="concat(';', $newline)"/> + <xsl:value-of select="concat('}', $newline)"/> + </xsl:if> + </xsl:otherwise> + </xsl:choose> + </xsl:for-each> + <xsl:value-of select="$newline" /> +</xsl:template> + +</xsl:stylesheet> diff --git a/target-avr/cpugen/xsl/utils.xsl b/target-avr/cpugen/xsl/utils.xsl new file mode 100644 index 0000000..4bd62eb --- /dev/null +++ b/target-avr/cpugen/xsl/utils.xsl @@ -0,0 +1,108 @@ +<?xml version="1.0"?> +<!-- + 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. +--> +<xsl:stylesheet version="1.0" + xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" + xmlns:str = "http://exslt.org/strings" + xmlns:func = "http://exslt.org/functions" + xmlns:exsl = "http://exslt.org/common" + xmlns:mine = "mrol...@gmail.com" + extension-element-prefixes="func"> + + <xsl:output method = "text" /> + <xsl:strip-space elements="*"/> + + <xsl:variable name="newline"> + <xsl:text> +</xsl:text> + </xsl:variable> + <xsl:variable name="license"> + <xsl:text>/* + * 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> + */ + +</xsl:text> + </xsl:variable> + + <xsl:variable name="tab"> + <xsl:text> </xsl:text> + </xsl:variable> + + <func:function name="mine:pad" as="string"> + <xsl:param name="str" as="xs:string"/> + <xsl:param name="len" as="xs:integer"/> + <xsl:variable name="lstr" select="string-length($str)"/> + <xsl:variable name="pad" select="str:padding($len - $lstr, ' ')"/> + <func:result select="concat($str,$pad)"/> + </func:function> + + <func:function name="mine:toupper" as="string"> + <xsl:param name="str" as="xs:string"/> + <xsl:variable name="upper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ ,-.'" /> + <xsl:variable name="lower" select="'abcdefghijklmnopqrstuvwxyz____'" /> + <func:result select="translate($str, $upper, $lower)" /> + </func:function> + + <func:function name="mine:toname" as="string"> + <xsl:param name="str" as="xs:string"/> + <xsl:variable name="src" select="'. ,-'" /> + <xsl:variable name="dst" select="'_'" /> + <func:result select="translate($str, $src, $dst)" /> + </func:function> + + <func:function name="mine:get-opcode-struct-type"> + <xsl:param name="length"/> + <xsl:choose> + <xsl:when test="$length < '9'"> + <func:result select="'uint8_t '"/> + </xsl:when> + <xsl:when test="$length < '17'"> + <func:result select="'uint16_t'"/> + </xsl:when> + <xsl:when test="$length < '33'"> + <func:result select="'uint32_t'"/> + </xsl:when> + <xsl:when test="$length < '65'"> + <func:result select="'uint64_t'"/> + </xsl:when> + </xsl:choose> + </func:function> + +</xsl:stylesheet> -- 2.4.9 (Apple Git-60)