#include <iostream>
#include <fstream>
#include <string>
#include "AXI_slave_if.h"
SC_MODULE(simple_LCD) {
public:
AXI_slave_if* s_if;
// Base address
sc_uint<32> base_address;
sc_uint<32>* data_buffer;
unsigned int LCD_hight;
unsigned int LCD_width;
unsigned int slave_read_delay;
unsigned int slave_write_delay;
// framebuf
sc_uint<8>* framebuf;
unsigned int framebuf_size;
void framebuf_read_delay() {
#ifdef VERBOSE
std::cout << std::endl << "===== " << this->name() << " (" << sc_time_stamp() << ")====" << std::endl;
std::cout << "Slave read delay start! : " << SLAVE_READ_DELAY << " cycles" << std::endl;
#endif
for (int i = 0; i < SLAVE_READ_DELAY; i++) {
wait(s_if->clk.posedge_event());
}
}
void framebuf_write_delay() {
#ifdef VERBOSE
std::cout << std::endl << "===== " << this->name() << " (" << sc_time_stamp() << ")====" << std::endl;
std::cout << "Slave write delay start! : " << SLAVE_READ_DELAY << " cycles" << std::endl;
#endif
for (int i = 0; i < SLAVE_WRITE_DELAY; i++) {
wait(s_if->clk.posedge_event());
}
}
void get_slave_data() {
wait();
while (1) {
std::map<sc_uint<2>, AXITransaction*>::iterator it = s_if->activeReads.begin();
if (it == s_if->activeReads.end()) {
// error condition
// if activewrite is empty exit simulation
// fix master simulation process module
cout << "[" << sc_time_stamp() << "] Read transfer error occured" << endl;
cout << "activeReads is empty" << endl;
exit(0);
}
// Slave read delay
for (int j = 0; j < slave_read_delay + 1; j++) {
if (j == slave_read_delay) { s_if->read_ready_event.notify(); }
wait(s_if->clk.posedge_event());
}
sc_uint<32> start_addr = it->second->addr;
sc_uint <3> byte = it->second->size; // simple slave un-support byte size
sc_uint <2> type = it->second->type;
sc_uint <4> len = it->second->len;
sc_uint<32> addr = start_addr;
s_if->Rlen = len;
s_if->Rid = it->second->ID;
sc_uint<32> tmp_data;
for (int i = 0; i < len + 1; i++) {
sc_uint<32> offset = addr - base_address;
switch (byte) {
case 0:
tmp_data.range(7, 0) = framebuf[offset];
break;
case 1:
tmp_data.range(15, 8) = framebuf[offset + 1];
tmp_data.range(7, 0) = framebuf[offset];
break;
case 2:
tmp_data.range(7, 0) = framebuf[offset + 0];
tmp_data.range(15, 8) = framebuf[offset + 1];
tmp_data.range(23, 16) = framebuf[offset + 2];
tmp_data.range(31, 24) = framebuf[offset + 3];
break;
default:
break;
}
addr = s_if->burst_addr_change(addr, start_addr, byte, type, len);
s_if->read_buffer = tmp_data;
s_if->set_read_data_event.notify();
wait(s_if->get_read_data_event);
}
wait();
}
}
void set_slave_data() {
wait();
while (1) {
std::map<sc_uint<2>, AXITransaction*>::iterator it = s_if->activeWrites.begin();
if (it == s_if->activeWrites.end()) {
// error condition
// if activewrite is empty exit simulation
// fix master simulation process module
cout << "[" << sc_time_stamp() << "] Write transfer error occured" << endl;
cout << "activeWrites is empty" << endl;
exit(0);
}
for (int j = 0; j < slave_write_delay + 1; j++) { wait(s_if->clk.posedge_event()); }
sc_uint<32> start_addr = it->second->addr;
sc_uint <3> byte = it->second->size;
sc_uint <2> type = it->second->type;
sc_uint <4> len = it->second->len;
sc_uint<32> addr = start_addr;
s_if->Wid = it->second->ID;
s_if->Wlen = len;
s_if->write_ready_event.notify();
for (int i = 0; i < len + 1; i++) {
wait(s_if->set_write_data_event);
sc_uint<32> offset = addr - base_address;
sc_uint<32> tmp_data = s_if->write_buffer;
switch (byte) {
case 0:
framebuf[offset] = tmp_data.range(7, 0);
if ((offset % (320 * 200)) == (320 * 200) - 1) {
printf_frame_buffer();
}
break;
case 1:
framebuf[offset + 0] = tmp_data.range(7, 0);
framebuf[offset + 1] = tmp_data.range(15, 8);
if ((offset % (320 * 200)) == (320 * 200) - 2) {
printf_frame_buffer();
}
break;
case 2:
framebuf[offset + 0] = tmp_data.range(7, 0);
framebuf[offset + 1] = tmp_data.range(15, 8);
framebuf[offset + 2] = tmp_data.range(23, 16);
framebuf[offset + 3] = tmp_data.range(31, 24);
if ((offset % (320 * 200)) == (320 * 200) - 4) {
printf_frame_buffer();
}
break;
default:
break;
}
addr = s_if->burst_addr_change(addr, start_addr, byte, type, len);
s_if->write_resp_event.notify();
}
wait();
}
return;
}
void printf_frame_buffer() {
std::string file_name = sc_time_stamp().to_string();
file_name.append("_simple_LCD.bmp");
ofstream outFile(file_name, std::ios::binary);
if (!outFile.is_open()) {
cout << sc_time_stamp() << "File is not opend in simple_LCD" << endl;
sc_stop();
}
outFile
<< (char)0x42 << (char)0x4D //bfType
<< (char)0xB6 << (char)0xBB << (char)0x00 << (char)0x00 //bfSize
<< (char)0x00 << (char)0x00 // 예약
<< (char)0x00 << (char)0x00 // 예약
<< (char)0x36 << (char)0x00 << (char)0x00 << (char)0x00 // 비트맵 데이터의 시작 위치
<< (char)0x28 << (char)0x00 << (char)0x00 << (char)0x00 // 현재 구조체의 크기
<< (char)0x40 << (char)0x01 << (char)0x00 << (char)0x00 // 비트맵 이미지의 가로 크기
<< (char)0xC8 << (char)0x00 << (char)0x00 << (char)0x00 // 비트맵 이미지의 세로 크기
<< (char)0x01 << (char)0x00 // 사용하는 색상판의 수
<< (char)0x18 << (char)0x00 // 픽셀 하나를 표현하는 비트 수
<< (char)0x00 << (char)0x00 << (char)0x00 << (char)0x00 // 압축 방식
<< (char)0x80 << (char)0xBB << (char)0x00 << (char)0x00 // 비트맵 이미지의 픽셀 데이터 크기
<< (char)0x00 << (char)0x00 << (char)0x00 << (char)0x00 // 그림의 가로 해상도(미터당 픽셀)
<< (char)0x00 << (char)0x00 << (char)0x00 << (char)0x00 // 그림의 세로 해상도(미터당 픽셀)
<< (char)0x00 << (char)0x00 << (char)0x00 << (char)0x00 // 비트맵을 표현하기 위해 필요한 색상 인덱스 수
<< (char)0x00 << (char)0x00 << (char)0x00 << (char)0x00;
for (int i = framebuf_size - 1; i >= 0; i--) {
outFile << (char)framebuf[i];
}
outFile.close();
}
SC_HAS_PROCESS(simple_LCD);
simple_LCD(sc_module_name _name, sc_uint<32> b_addr, unsigned int hight, unsigned int width) {
s_if = new AXI_slave_if("simple_slave_if", b_addr, hight * width * 3);
slave_read_delay = 40;
slave_write_delay = 40;
base_address = b_addr;
framebuf_size = hight * width * 3; // rgb
framebuf = new sc_uint<8>[framebuf_size];
SC_THREAD(set_slave_data);
sensitive << s_if->write_reg_event;
SC_THREAD(get_slave_data);
sensitive << s_if->read_reg_event;
}
};