2021-08-11 19:23:00 +00:00
|
|
|
/* 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.
|
|
|
|
* */
|
2021-08-11 07:04:59 +00:00
|
|
|
#include <iostream>
|
|
|
|
#include <fstream>
|
2021-08-12 18:37:15 +00:00
|
|
|
#include <sstream>
|
2021-08-12 20:14:53 +00:00
|
|
|
#include <cstring>
|
2021-08-11 07:04:59 +00:00
|
|
|
|
|
|
|
enum ExitStatus {
|
|
|
|
BAD_ARGUMENT = 1,
|
|
|
|
FILE_NOT_OPEN = 2,
|
|
|
|
FILE_BAD_FORMAT = 3
|
|
|
|
};
|
|
|
|
|
|
|
|
int main(int argc, char** argv) {
|
2021-08-12 16:26:03 +00:00
|
|
|
if (argc < 2) {
|
2021-08-11 07:04:59 +00:00
|
|
|
return BAD_ARGUMENT;
|
|
|
|
}
|
2021-08-12 18:37:15 +00:00
|
|
|
const int images = argc - 1;
|
|
|
|
std::stringstream jump_table;
|
|
|
|
std::stringstream asm_code;
|
2021-08-11 07:04:59 +00:00
|
|
|
|
|
|
|
std::fstream outfile;
|
|
|
|
outfile.open("frame.S", std::ios::out);
|
|
|
|
if (! outfile) {
|
|
|
|
return FILE_NOT_OPEN;
|
|
|
|
}
|
|
|
|
|
2021-08-12 18:37:15 +00:00
|
|
|
jump_table << "#include \"macro.h\"" << std::endl;
|
|
|
|
jump_table << "#include <avr/io.h>" << std::endl;
|
2021-08-11 07:04:59 +00:00
|
|
|
|
2021-08-12 18:37:15 +00:00
|
|
|
char** image = new char*[images];
|
|
|
|
|
|
|
|
for (int current_image = 0; current_image < images; ++current_image) {
|
2021-08-12 16:26:03 +00:00
|
|
|
std::fstream infile;
|
2021-08-12 18:37:15 +00:00
|
|
|
|
2021-08-12 16:26:03 +00:00
|
|
|
infile.open(argv[1 + current_image], std::ios::in);
|
|
|
|
if (! infile) {
|
|
|
|
return FILE_NOT_OPEN;
|
|
|
|
}
|
2021-08-11 07:04:59 +00:00
|
|
|
|
2021-08-12 16:26:03 +00:00
|
|
|
int width, height;
|
|
|
|
std::string format;
|
|
|
|
char c;
|
2021-08-11 07:04:59 +00:00
|
|
|
|
2021-08-12 16:26:03 +00:00
|
|
|
getline(infile, format);
|
2021-08-11 07:04:59 +00:00
|
|
|
|
2021-08-12 16:26:03 +00:00
|
|
|
std::cout << format << std::endl;
|
2021-08-11 07:04:59 +00:00
|
|
|
|
2021-08-12 16:26:03 +00:00
|
|
|
if (format != "P1") {
|
|
|
|
return FILE_BAD_FORMAT;
|
2021-08-11 07:04:59 +00:00
|
|
|
}
|
|
|
|
|
2021-08-12 16:26:03 +00:00
|
|
|
// skip one line TODO
|
|
|
|
getline(infile, format);
|
|
|
|
std::cout << format << std::endl;
|
|
|
|
|
|
|
|
infile >> width >> height;
|
|
|
|
std::cout << width << " x " << height << std::endl;
|
|
|
|
|
2021-08-12 18:37:15 +00:00
|
|
|
image[current_image] = new char[height * width];
|
2021-08-12 16:26:03 +00:00
|
|
|
|
|
|
|
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') {
|
2021-08-12 18:37:15 +00:00
|
|
|
image[current_image][y * width + x] = c;
|
2021-08-12 16:26:03 +00:00
|
|
|
x++;
|
|
|
|
} else {
|
|
|
|
continue;
|
2021-08-11 07:04:59 +00:00
|
|
|
}
|
2021-08-12 16:26:03 +00:00
|
|
|
}
|
|
|
|
y++;
|
|
|
|
}
|
2021-08-11 07:04:59 +00:00
|
|
|
|
2021-08-12 16:26:03 +00:00
|
|
|
infile.close();
|
|
|
|
|
2021-08-12 20:14:53 +00:00
|
|
|
jump_table << ".global line_jump_table_" << current_image << std::endl;
|
|
|
|
jump_table << "line_jump_table_" << current_image << ":" << std::endl;
|
|
|
|
|
2021-08-12 16:26:03 +00:00
|
|
|
for (int y = 0; y < height; ++y) {
|
2021-08-12 20:14:53 +00:00
|
|
|
|
|
|
|
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;
|
2021-08-12 18:37:15 +00:00
|
|
|
asm_code << "line_" << current_image << "_" << y << ":" << std::endl;
|
2021-08-12 16:26:03 +00:00
|
|
|
|
|
|
|
int count = 0;
|
2021-08-12 18:37:15 +00:00
|
|
|
char last = image[current_image][y * width + 0];
|
2021-08-12 16:26:03 +00:00
|
|
|
|
|
|
|
for (int x = 0; x < width; ++x) {
|
2021-08-12 18:37:15 +00:00
|
|
|
char current = image[current_image][y * width + x];
|
2021-08-12 16:26:03 +00:00
|
|
|
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;
|
2021-08-12 18:37:15 +00:00
|
|
|
asm_code << '\t' << "cbi IO(PORTB), 4" << std::endl;
|
2021-08-12 16:26:03 +00:00
|
|
|
} else if (last == '1') {
|
|
|
|
std::cout << "set" << std::endl;
|
2021-08-12 18:37:15 +00:00
|
|
|
asm_code << '\t' << "sbi IO(PORTB), 4" << std::endl;
|
2021-08-12 16:26:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (count > 1) {
|
2021-08-12 18:37:15 +00:00
|
|
|
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;
|
2021-08-12 16:26:03 +00:00
|
|
|
}
|
|
|
|
|
2021-08-12 18:37:15 +00:00
|
|
|
asm_code << '\t' << "rjmp 2f" << std::endl;
|
|
|
|
asm_code << "2:" << std::endl;
|
2021-08-12 16:26:03 +00:00
|
|
|
|
|
|
|
last = current;
|
|
|
|
count = 1;
|
2021-08-11 07:04:59 +00:00
|
|
|
}
|
|
|
|
}
|
2021-08-12 18:37:15 +00:00
|
|
|
asm_code << '\t' << "cbi IO(PORTB), 4" << std::endl;
|
|
|
|
asm_code << '\t' << "jmp jump_table_return_address" << std::endl;
|
2021-08-11 07:04:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-08-12 18:37:15 +00:00
|
|
|
delete[] image;
|
|
|
|
|
|
|
|
outfile << jump_table.str() << asm_code.str();
|
2021-08-11 07:04:59 +00:00
|
|
|
|
|
|
|
outfile.close();
|
|
|
|
}
|