/* frame.cpp * Takes a black/white (1bpp) PNM ASCII-armored image as input, * and produces the frame.S assembly code to draw it * as an analog video signal for this project's kernel. * */ #include #include #include #include enum ExitStatus { BAD_ARGUMENT = 1, FILE_NOT_OPEN = 2, FILE_BAD_FORMAT = 3 }; int main(int argc, char** argv) { if (argc < 2) { return BAD_ARGUMENT; } const int images = argc - 1; std::stringstream jump_table; std::stringstream asm_code; std::fstream outfile; outfile.open("frame.S", std::ios::out); if (! outfile) { return FILE_NOT_OPEN; } jump_table << "#include \"macro.h\"" << std::endl; jump_table << "#include " << std::endl; char** image = new char*[images]; for (int current_image = 0; current_image < images; ++current_image) { std::fstream infile; infile.open(argv[1 + current_image], std::ios::in); if (! infile) { return FILE_NOT_OPEN; } int width, height; std::string format; char c; getline(infile, format); std::cout << format << std::endl; if (format != "P1") { return FILE_BAD_FORMAT; } // skip one line TODO getline(infile, format); std::cout << format << std::endl; infile >> width >> height; std::cout << width << " x " << height << std::endl; image[current_image] = new char[height * width]; for (int y = 0; y < height; ) { for (int x = 0; x < width; ) { c = infile.get(); if (! infile.good()) return FILE_BAD_FORMAT; if (c == '0' || c == '1') { image[current_image][y * width + x] = c; x++; } else { continue; } } y++; } infile.close(); jump_table << ".global line_jump_table_" << current_image << std::endl; jump_table << "line_jump_table_" << current_image << ":" << std::endl; for (int y = 0; y < height; ++y) { int diff = 1; for (int other_image = 0; other_image <= current_image; ++other_image) { for (int other_y = 0; other_y < height && other_y < y; ++other_y) { diff = memcmp(&(image[current_image][y * width + 0]), &(image[other_image][other_y * width + 0]), width); if (diff == 0) { jump_table << '\t' << "jmp line_" << other_image << "_" << other_y << std::endl; goto nested_loop_end; } } } nested_loop_end: if (diff == 0) continue; jump_table << '\t' << "jmp line_" << current_image << "_" << y << std::endl; asm_code << "line_" << current_image << "_" << y << ":" << std::endl; int count = 0; char last = image[current_image][y * width + 0]; for (int x = 0; x < width; ++x) { char current = image[current_image][y * width + x]; std::cout << "current " << current << " last " << last << std::endl; if (current == last) { ++count; } else { std::cout << "detected change" << std::endl; if (last == '0') { std::cout << "clear" << std::endl; asm_code << '\t' << "cbi IO(PORTB), 4" << std::endl; } else if (last == '1') { std::cout << "set" << std::endl; asm_code << '\t' << "sbi IO(PORTB), 4" << std::endl; } if (count > 1) { asm_code << '\t' << "ldi r31, " << count - 1 << std::endl; asm_code << "1:" << std::endl; asm_code << '\t' << "dec r31" << std::endl; asm_code << '\t' << "nop" << std::endl; asm_code << '\t' << "brne 1b" << std::endl; } asm_code << '\t' << "rjmp 2f" << std::endl; asm_code << "2:" << std::endl; last = current; count = 1; } } asm_code << '\t' << "cbi IO(PORTB), 4" << std::endl; asm_code << '\t' << "jmp jump_table_return_address" << std::endl; } } delete[] image; outfile << jump_table.str() << asm_code.str(); outfile.close(); }