diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2edb906 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.o +*.d \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..f14a40e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,79 @@ +{ + "files.associations": { + "*.ejs": "html", + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "csetjmp": "cpp", + "csignal": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "any": "cpp", + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "bitset": "cpp", + "cfenv": "cpp", + "charconv": "cpp", + "chrono": "cpp", + "cinttypes": "cpp", + "codecvt": "cpp", + "complex": "cpp", + "condition_variable": "cpp", + "cstdint": "cpp", + "cuchar": "cpp", + "deque": "cpp", + "forward_list": "cpp", + "list": "cpp", + "map": "cpp", + "set": "cpp", + "unordered_map": "cpp", + "unordered_set": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "optional": "cpp", + "random": "cpp", + "ratio": "cpp", + "regex": "cpp", + "string": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "fstream": "cpp", + "future": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "mutex": "cpp", + "new": "cpp", + "ostream": "cpp", + "scoped_allocator": "cpp", + "shared_mutex": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "thread": "cpp", + "typeindex": "cpp", + "typeinfo": "cpp", + "valarray": "cpp", + "variant": "cpp" + } +} \ No newline at end of file diff --git a/atpg b/atpg new file mode 100755 index 0000000..61b9f2d Binary files /dev/null and b/atpg differ diff --git a/c432.bench b/c432.bench new file mode 100644 index 0000000..f020905 --- /dev/null +++ b/c432.bench @@ -0,0 +1,207 @@ +# c432 + +INPUT(1) +INPUT(4) +INPUT(8) +INPUT(11) +INPUT(14) +INPUT(17) +INPUT(21) +INPUT(24) +INPUT(27) +INPUT(30) +INPUT(34) +INPUT(37) +INPUT(40) +INPUT(43) +INPUT(47) +INPUT(50) +INPUT(53) +INPUT(56) +INPUT(60) +INPUT(63) +INPUT(66) +INPUT(69) +INPUT(73) +INPUT(76) +INPUT(79) +INPUT(82) +INPUT(86) +INPUT(89) +INPUT(92) +INPUT(95) +INPUT(99) +INPUT(102) +INPUT(105) +INPUT(108) +INPUT(112) +INPUT(115) + +OUTPUT(223) +OUTPUT(329) +OUTPUT(370) +OUTPUT(421) +OUTPUT(430) +OUTPUT(431) +OUTPUT(432) + +118 = NOT(1) +119 = NOT(4) +122 = NOT(11) +123 = NOT(17) +126 = NOT(24) +127 = NOT(30) +130 = NOT(37) +131 = NOT(43) +134 = NOT(50) +135 = NOT(56) +138 = NOT(63) +139 = NOT(69) +142 = NOT(76) +143 = NOT(82) +146 = NOT(89) +147 = NOT(95) +150 = NOT(102) +151 = NOT(108) +154 = NAND(118, 4) +157 = NOR(8, 119) +158 = NOR(14, 119) +159 = NAND(122, 17) +162 = NAND(126, 30) +165 = NAND(130, 43) +168 = NAND(134, 56) +171 = NAND(138, 69) +174 = NAND(142, 82) +177 = NAND(146, 95) +180 = NAND(150, 108) +183 = NOR(21, 123) +184 = NOR(27, 123) +185 = NOR(34, 127) +186 = NOR(40, 127) +187 = NOR(47, 131) +188 = NOR(53, 131) +189 = NOR(60, 135) +190 = NOR(66, 135) +191 = NOR(73, 139) +192 = NOR(79, 139) +193 = NOR(86, 143) +194 = NOR(92, 143) +195 = NOR(99, 147) +196 = NOR(105, 147) +197 = NOR(112, 151) +198 = NOR(115, 151) +199 = AND(154, 159, 162, 165, 168, 171, 174, 177, 180) +203 = NOT(199) +213 = NOT(199) +223 = NOT(199) +224 = XOR(203, 154) +227 = XOR(203, 159) +230 = XOR(203, 162) +233 = XOR(203, 165) +236 = XOR(203, 168) +239 = XOR(203, 171) +242 = NAND(1, 213) +243 = XOR(203, 174) +246 = NAND(213, 11) +247 = XOR(203, 177) +250 = NAND(213, 24) +251 = XOR(203, 180) +254 = NAND(213, 37) +255 = NAND(213, 50) +256 = NAND(213, 63) +257 = NAND(213, 76) +258 = NAND(213, 89) +259 = NAND(213, 102) +260 = NAND(224, 157) +263 = NAND(224, 158) +264 = NAND(227, 183) +267 = NAND(230, 185) +270 = NAND(233, 187) +273 = NAND(236, 189) +276 = NAND(239, 191) +279 = NAND(243, 193) +282 = NAND(247, 195) +285 = NAND(251, 197) +288 = NAND(227, 184) +289 = NAND(230, 186) +290 = NAND(233, 188) +291 = NAND(236, 190) +292 = NAND(239, 192) +293 = NAND(243, 194) +294 = NAND(247, 196) +295 = NAND(251, 198) +296 = AND(260, 264, 267, 270, 273, 276, 279, 282, 285) +300 = NOT(263) +301 = NOT(288) +302 = NOT(289) +303 = NOT(290) +304 = NOT(291) +305 = NOT(292) +306 = NOT(293) +307 = NOT(294) +308 = NOT(295) +309 = NOT(296) +319 = NOT(296) +329 = NOT(296) +330 = XOR(309, 260) +331 = XOR(309, 264) +332 = XOR(309, 267) +333 = XOR(309, 270) +334 = NAND(8, 319) +335 = XOR(309, 273) +336 = NAND(319, 21) +337 = XOR(309, 276) +338 = NAND(319, 34) +339 = XOR(309, 279) +340 = NAND(319, 47) +341 = XOR(309, 282) +342 = NAND(319, 60) +343 = XOR(309, 285) +344 = NAND(319, 73) +345 = NAND(319, 86) +346 = NAND(319, 99) +347 = NAND(319, 112) +348 = NAND(330, 300) +349 = NAND(331, 301) +350 = NAND(332, 302) +351 = NAND(333, 303) +352 = NAND(335, 304) +353 = NAND(337, 305) +354 = NAND(339, 306) +355 = NAND(341, 307) +356 = NAND(343, 308) +357 = AND(348, 349, 350, 351, 352, 353, 354, 355, 356) +360 = NOT(357) +370 = NOT(357) +371 = NAND(14, 360) +372 = NAND(360, 27) +373 = NAND(360, 40) +374 = NAND(360, 53) +375 = NAND(360, 66) +376 = NAND(360, 79) +377 = NAND(360, 92) +378 = NAND(360, 105) +379 = NAND(360, 115) +380 = NAND(4, 242, 334, 371) +381 = NAND(246, 336, 372, 17) +386 = NAND(250, 338, 373, 30) +393 = NAND(254, 340, 374, 43) +399 = NAND(255, 342, 375, 56) +404 = NAND(256, 344, 376, 69) +407 = NAND(257, 345, 377, 82) +411 = NAND(258, 346, 378, 95) +414 = NAND(259, 347, 379, 108) +415 = NOT(380) +416 = AND(381, 386, 393, 399, 404, 407, 411, 414) +417 = NOT(393) +418 = NOT(404) +419 = NOT(407) +420 = NOT(411) +421 = NOR(415, 416) +422 = NAND(386, 417) +425 = NAND(386, 393, 418, 399) +428 = NAND(399, 393, 419) +429 = NAND(386, 393, 407, 420) +430 = NAND(381, 386, 422, 399) +431 = NAND(381, 386, 425, 428) +432 = NAND(381, 422, 425, 429) diff --git a/circuit.cpp b/circuit.cpp new file mode 100644 index 0000000..e69de29 diff --git a/circuit.h b/circuit.h new file mode 100644 index 0000000..eba71d0 --- /dev/null +++ b/circuit.h @@ -0,0 +1,20 @@ +#include +#include +#include + +class Gate { +public: + std::string name; + enum { AND, NAND, OR, NOR, XOR, XNOR, NOT, BUF, INPUT, OUTPUT } type; + enum { VAL_ZERO, VAL_ONE, VAL_X } value; + std::vector outputs; + std::vector inputs; +}; + +class Circuit { +public: +std::vector PIs; +std::vector POs; +std::unordered_map name2gate; +void parse_from_file(const char *filename); +}; \ No newline at end of file diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..1a666f4 --- /dev/null +++ b/main.cpp @@ -0,0 +1,26 @@ +#include +#include + + +#include "circuit.h" + +int main(int args, char* argv[]) { + + if(args != 2) { + printf("usage: ./atpg \n"); + exit(1); + } + + Circuit circuit; + + printf("parsing file %s...\n", argv[1]); + circuit.parse_from_file(argv[1]); + printf("====== Circuit Statistics ====== \n"); + printf("PI:\t%d\n", circuit.PIs.size()); + printf("PO:\t%d\n", circuit.POs.size()); + printf("Gates:\t%d\n", circuit.name2gate.size()); + + + + return 0; +} \ No newline at end of file diff --git a/makefile b/makefile new file mode 100644 index 0000000..386f998 --- /dev/null +++ b/makefile @@ -0,0 +1,72 @@ +#一个实用的makefile,能自动编译当前目录下所有.c/.cpp源文件,支持二者混合编译 +#并且当某个.c/.cpp、.h或依赖的源文件被修改后,仅重编涉及到的源文件,未涉及的不编译 +#详解文档:http://blog.csdn.net/huyansoft/article/details/8924624 +#author:胡彦 2013-5-21 + +#---------------------------------------------------------- +#编译工具用g++,以同时支持C和C++程序,以及二者的混合编译 +CC=g++ + +CPPFLAGS=-O3 + +#使用$(winldcard *.c)来获取工作目录下的所有.c文件的列表 +#sources:=main.cpp command.c + +#变量sources得到当前目录下待编译的.c/.cpp文件的列表,两次调用winldcard、结果连在一起即可 +sources:=$(wildcard *.c) $(wildcard *.cpp) + +#变量objects得到待生成的.o文件的列表,把sources中每个文件的扩展名换成.o即可。这里两次调用patsubst函数,第1次把sources中所有.cpp换成.o,第2次把第1次结果里所有.c换成.o +objects:=$(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(sources))) + +#变量dependence得到待生成的.d文件的列表,把objects中每个扩展名.o换成.d即可。也可写成$(patsubst %.o,%.d,$(objects)) +dependence:=$(objects:.o=.d) + +#---------------------------------------------------------- +#当$(objects)列表里所有文件都生成后,便可调用这里的 $(CC) $^ -o $@ 命令生成最终目标all了 +#把all定义成第1个规则,使得可以把make all命令简写成make +atpg: $(objects) + $(CC) $(CPPFLAGS) $^ -o $@ +# @./$@ #编译后立即执行 + +#这段使用make的模式规则,指示如何由.c文件生成.o,即对每个.c文件,调用gcc -c XX.c -o XX.o命令生成对应的.o文件 +#如果不写这段也可以,因为make的隐含规则可以起到同样的效果 +%.o: %.c + $(CC) $(CPPFLAGS) -c $< -o $@ + +#同上,指示如何由.cpp生成.o,可省略 +%.o: %.cpp + $(CC) $(CPPFLAGS) -c $< -o $@ + +#---------------------------------------------------------- +include $(dependence) #注意该句要放在终极目标all的规则之后,否则.d文件里的规则会被误当作终极规则了 + +#因为这4行命令要多次凋用,定义成命令包以简化书写 +define gen_dep +set -e; rm -f $@; \ +$(CC) -MM $(CPPFLAGS) $< > $@.$$$$; \ +sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ +rm -f $@.$$$$ +endef + +#指示如何由.c生成其依赖规则文件.d +#这段使用make的模式规则,指示对每个.c文件,如何生成其依赖规则文件.d,调用上面的命令包即可 +%.d: %.c + $(gen_dep) + +#同上,指示对每个.cpp,如何生成其依赖规则文件.d +%.d: %.cpp + $(gen_dep) + +#---------------------------------------------------------- +#清除所有临时文件(所有.o和.d)。之所以把clean定义成伪目标,是因为这个目标并不对应实际的文件 +.PHONY: clean +clean: #.$$已在每次使用后立即删除。-f参数表示被删文件不存在时不报错 + rm -f all $(objects) $(dependence) + +echo: #调试时显示一些变量的值 + @echo sources=$(sources) + @echo objects=$(objects) + @echo dependence=$(dependence) + @echo CPPFLAGS=$(CPPFLAGS) + +#提醒:当混合编译.c/.cpp时,为了能够在C++程序里调用C函数,必须把每一个要调用的C函数,其声明都包括在extern "C"{}块里面,这样C++链接时才能成功链接它们。 \ No newline at end of file diff --git a/parser.cpp b/parser.cpp new file mode 100644 index 0000000..906798b --- /dev/null +++ b/parser.cpp @@ -0,0 +1,101 @@ +#include "circuit.h" + +#include +#include +#include +#include +#include + +std::string trim(const std::string& s) { + auto wsfront = std::find_if_not(s.begin(), s.end(), [](int c){ return std::isspace(c); }); + auto wsback = std::find_if_not(s.rbegin(), s.rend(), [](int c){ return std::isspace(c); }).base(); + return (wsback <= wsfront ? std::string() : std::string(wsfront, wsback)); +} + +void Circuit::parse_from_file(const char *filename) { + + std::ifstream file(filename); + if(!file.is_open()) { + printf("Error while reading %s\n", filename); + exit(1); + } + + // buf 10MB + file.rdbuf()->pubsetbuf(0, 10 *1024 * 1024); + + std::string line; + while(std::getline(file, line)) { + if(line[0] == '#') continue; + if(line == "\r" || line == "") continue; + + std::cmatch m; + if(std::regex_match(line.c_str(), m, std::regex("INPUT\\s*\\(\\s*(.*)\\s*\\)\\s*"))) { + + Gate *input = new Gate(); + input->name = m.str(1); + input->type = Gate::INPUT; + input->value = Gate::VAL_X; + name2gate.insert(std::make_pair(input->name, input)); + + + std::cout << "input -> $" << input->name << "$" << std::endl; + + PIs.push_back(input); + } else if(std::regex_match(line.c_str(), m, std::regex("OUTPUT\\s*\\(\\s*(.*)\\s*\\)\\s*"))) { + + Gate *output = new Gate(); + output->name = m.str(1); + output->type = Gate::OUTPUT; + output->value = Gate::VAL_X; + name2gate.insert(std::make_pair(output->name, output)); + + POs.push_back(output); + } else if(std::regex_match(line.c_str(), m, std::regex("\\s*(\\S+)\\s*=\\s*(\\w+)\\s*\\(\\s*(.*)\\s*\\)\\s*"))) { + + std::string output_name = m.str(1); + std::string gate_name = m.str(2); + std::string list = m.str(3); + + Gate *gate = new Gate(); + + gate->name = output_name; + gate->value = Gate::VAL_X; + + name2gate.insert(std::make_pair(gate->name, gate)); + + // split by "," + std::regex pattern(R"(\s*,\s*)"); + std::sregex_token_iterator it(list.begin(), list.end(), pattern, -1); + std::sregex_token_iterator end; + + while (it != end) { + std::string in = trim(*it++); + if(!name2gate.count(in)) { + printf("Error while reading file: $%s$ is not defined before used.\n", in.c_str()); + exit(1); + } + Gate* in_gate = name2gate[in]; + + gate->inputs.push_back(in_gate); + in_gate->outputs.push_back(gate); + } + + if(gate_name == "AND") { gate->type = Gate::AND; } + else if(gate_name == "NAND") { gate->type = Gate::NAND; } + else if(gate_name == "OR") { gate->type = Gate::OR; } + else if(gate_name == "NOR") { gate->type = Gate::NOR; } + else if(gate_name == "XOR") { gate->type = Gate::XOR; } + else if(gate_name == "XNOR") { gate->type = Gate::XNOR; } + else if(gate_name == "NOT") { gate->type = Gate::NOT; } + else if(gate_name == "BUF") { gate->type = Gate::BUF; } + else { + printf("Error while reading file: %s is not a valid gate.\n", gate_name.c_str()); + exit(1); + } + + } else { + printf("Error while reading file: \"%s\" is a wrong line.\n", line.c_str()); + exit(1); + } + } +} \ No newline at end of file