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>
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::fstream infile;
|
|
|
|
infile.open(argv[1], std::ios::in);
|
|
|
|
if (! infile) {
|
|
|
|
return FILE_NOT_OPEN;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::fstream outfile;
|
|
|
|
outfile.open("frame.S", std::ios::out);
|
|
|
|
if (! outfile) {
|
|
|
|
return FILE_NOT_OPEN;
|
|
|
|
}
|
|
|
|
|
|
|
|
outfile << "#include \"macro.h\"" << std::endl;
|
|
|
|
outfile << "#include <avr/io.h>" << std::endl;
|
|
|
|
|
|
|
|
outfile << ".global line_jump_table" << std::endl;
|
|
|
|
outfile << "line_jump_table:" << std::endl;
|
|
|
|
for (int i = 0; i < 256; ++i) {
|
|
|
|
outfile << '\t' << "jmp line_" << i << std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
char* 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[y * width + x] = c;
|
|
|
|
x++;
|
|
|
|
} else {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
y++;
|
|
|
|
}
|
|
|
|
|
|
|
|
infile.close();
|
|
|
|
|
|
|
|
for (int y = 0; y < height; ++y) {
|
|
|
|
outfile << "line_" << y << ":" << std::endl;
|
|
|
|
|
|
|
|
int count = 0;
|
|
|
|
char last = image[y * width + 0];
|
|
|
|
|
|
|
|
for (int x = 0; x < width; ++x) {
|
|
|
|
char 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;
|
|
|
|
outfile << '\t' << "cbi IO(PORTB), 4" << std::endl;
|
|
|
|
} else if (last == '1') {
|
|
|
|
std::cout << "set" << std::endl;
|
|
|
|
outfile << '\t' << "sbi IO(PORTB), 4" << std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count > 1) {
|
|
|
|
outfile << '\t' << "ldi r31, " << count - 1 << std::endl;
|
|
|
|
outfile << "1:" << std::endl;
|
|
|
|
outfile << '\t' << "dec r31" << std::endl;
|
|
|
|
outfile << '\t' << "nop" << std::endl;
|
|
|
|
outfile << '\t' << "brne 1b" << std::endl;
|
|
|
|
}
|
|
|
|
|
fixed horizontal offset error
Basically, the LPM instruction (3 cycles) does not always take 3 cycles,
(I think because of the timing needed to read the Flash memory),
and this disrupts the timing of the signal, leading to some offsets
depending on what is shown on the line.
Thus, the LPM instruction has been replaced with an RJMP one, which,
instead, always takes 3 perfect cycles to be performed, timing is
not disrupted anymore, and image appears ok.
2021-08-11 09:24:41 +00:00
|
|
|
outfile << '\t' << "rjmp 2f" << std::endl;
|
|
|
|
outfile << "2:" << std::endl;
|
2021-08-11 07:04:59 +00:00
|
|
|
|
|
|
|
last = current;
|
|
|
|
count = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
outfile << '\t' << "cbi IO(PORTB), 4" << std::endl;
|
|
|
|
outfile << '\t' << "jmp jump_table_return_address" << std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
outfile.close();
|
|
|
|
}
|