//
// handshake_test.cpp
// 2015/05/24
// by marsee
//
#include <stdio.h>
#include <string.h>
#include <cmath>
void handshake_test(float cntin, float *cntout){
#pragma HLS PIPELINE
#pragma HLS INTERFACE ap_hs register port=cntin
#pragma HLS INTERFACE ap_hs register port=cntout
#pragma HLS INTERFACE ap_ctrl_none port=return
*cntout = log(cntin);
}
//
// handshake_test.cpp
// 2015/05/24
// by marsee
//
#include <stdio.h>
#include <string.h>
#include <cmath>
void handshake_test(float cntin, float *cntout){
#pragma HLS PIPELINE
#pragma HLS INTERFACE ap_hs register port=cntin
#pragma HLS INTERFACE ap_hs register port=cntout
#pragma HLS INTERFACE ap_ctrl_none port=return
*cntout = cos(cntin);
}
//
// handshake_test.cpp
// 2015/05/17
// by marsee
//
#include <stdio.h>
#include <string.h>
#include <ap_int.h>
#include <cmath>
void handshake_test(ap_uint<8> cntin, ap_uint<8> *cntout){
#pragma HLS PIPELINE
#pragma HLS INTERFACE ap_hs register port=cntin
#pragma HLS INTERFACE ap_hs register port=cntout
#pragma HLS INTERFACE ap_ctrl_none port=return
float fsqrt_data;
fsqrt_data = sqrt((float)cntin);
*cntout = (ap_int<8>)fsqrt_data;
}
これでは倍精度浮動小数点演算だった。*cntout = (ap_uint<8>)sqrt((float)cntin);
//
// handshake_test.cpp
// 2015/05/24
// by marsee
//
#include <stdio.h>
#include <string.h>
#include <cmath>
void handshake_test(float cntin, float *cntout){
#pragma HLS PIPELINE
#pragma HLS INTERFACE ap_hs register port=cntin
#pragma HLS INTERFACE ap_hs register port=cntout
#pragma HLS INTERFACE ap_ctrl_none port=return
*cntout = sqrt(cntin);
}
//
// handshake_test_tb.cpp
// 2015/05/24
// by marsee
//
#include <stdio.h>
#include <string.h>
#include <ap_int.h>
void handshake_test(float cntin, float *cntout);
int main(){
using namespace std;
float result;
float *cntout;
cntout = &result;
for(int i=0; i<10; i++){
handshake_test((float)i, cntout);
cout << "i = " << i << " " << "result = " << result << endl;
}
return 0;
}
C/RTL コシミュレーション波形が表示された。cd C:/Users/Masaaki/Documents/Vivado_HLS/study/handshake_test/solution1/sim/verilog
current_fileset
open_wave_database handshake_test.wdb
open_wave_config handshake_test.wcfg
//
// handshake_test.cpp
// 2015/05/17
// by marsee
//
#include <stdio.h>
#include <string.h>
#include <ap_int.h>
void handshake_test(ap_uint<8> cntin, ap_uint<8> *cntout){
#pragma HLS PIPELINE
#pragma HLS INTERFACE ap_hs register port=cntin
#pragma HLS INTERFACE ap_hs register port=cntout
#pragma HLS INTERFACE ap_ctrl_none port=return
*cntout = sqrt(cntin);
}
//
// handshake_test_tb.cpp
// 2015/05/18
// by marsee
//
#include <stdio.h>
#include <string.h>
#include <ap_int.h>
void handshake_test(ap_uint<8> cntin, ap_uint<8> *cntout);
int main(){
using namespace std;
ap_uint<8> result;
ap_uint<8> *cntout;
cntout = &result;
for(int i=0; i<10; i++){
handshake_test((ap_uint<8>)i, cntout);
cout << "i = " << i << " " << "result = " << result << endl;
}
return 0;
}
register オプションについては、ツィッターで tu1978 さんと Vengineer さんに教えて頂きました。ありがとうございました。
C/RTL コシミュレーション波形が表示された。cd C:/Users/Masaaki/Documents/Vivado_HLS/study/handshake_test/solution1/sim/verilog
current_fileset
open_wave_database handshake_test.wdb
open_wave_config handshake_test.wcfg
が追加されているのが分かる。cntin_V_ap_vld
cntin_V_ap_ack
cntout_V_ap_vld
cntout_V_ap_ack
//
// handshake_test_tb.v
// 2015/05/18
// by marsee
//
`default_nettype none
`timescale 100ps / 1ps
module handshake_test_tb;
function [7:0] mseqf8_0(input [7:0] din);
reg xor_result;
begin
xor_result = din[7] ^ din[3] ^ din[2] ^ din[1];
mseqf8_0 = {din[6:0], xor_result};
end
endfunction
function [7:0] mseqf8_1(input [7:0] din);
reg xor_result;
begin
xor_result = din[7] ^ din[5] ^ din[4] ^ din[1];
mseqf8_1 = {din[6:0], xor_result};
end
endfunction
wire ap_clk;
wire ap_rst;
reg [7:0] cntin_V;
wire cntin_V_ap_vld;
wire cntin_V_ap_ack;
wire [7:0] cntout_V;
wire cntout_V_ap_vld;
wire cntout_V_ap_ack;
reg [7:0] random8_0;
reg [7:0] random8_1;
handshake_test uut (
.ap_clk(ap_clk),
.ap_rst(ap_rst),
.cntin_V(cntin_V),
.cntin_V_ap_vld(cntin_V_ap_vld),
.cntin_V_ap_ack(cntin_V_ap_ack),
.cntout_V(cntout_V),
.cntout_V_ap_vld(cntout_V_ap_vld),
.cntout_V_ap_ack(cntout_V_ap_ack)
);
always @(posedge ap_clk) begin
if (ap_rst) begin
random8_0 <= 8'd1;
end else begin
random8_0 <= mseqf8_0(random8_0);
end
end
always @(posedge ap_clk) begin
if (ap_rst) begin
random8_1 <= 8'd1;
end else begin
random8_1 <= mseqf8_1(random8_1);
end
end
assign cntin_V_ap_vld = random8_0[0];
assign cntout_V_ap_ack = random8_1[0];
always @(posedge ap_clk) begin
if (ap_rst) begin
cntin_V <= 8'd0;
end else if (cntin_V_ap_vld & cntin_V_ap_ack) begin
cntin_V <= cntin_V + 8'd1;
end
end
// ap_clk
clk_gen #(
.CLK_PERIOD(100), // 10.0nsec, 100MHz
.CLK_DUTY_CYCLE(0.5),
.CLK_OFFSET(0),
.START_STATE(1'b0)
) ap_clk_i (
.clk_out(ap_clk)
);
// ap_rst
reset_gen #(
.RESET_STATE(1'b1),
.RESET_TIME(1000) // 100nsec
) RESETi (
.reset_out(ap_rst)
);
endmodule
module clk_gen #(
parameter CLK_PERIOD = 100,
parameter real CLK_DUTY_CYCLE = 0.5,
parameter CLK_OFFSET = 0,
parameter START_STATE = 1'b0 )
(
output reg clk_out
);
begin
initial begin
#CLK_OFFSET;
forever
begin
clk_out = START_STATE;
#(CLK_PERIOD-(CLK_PERIOD*CLK_DUTY_CYCLE)) clk_out = ~START_STATE;
#(CLK_PERIOD*CLK_DUTY_CYCLE);
end
end
end
endmodule
module reset_gen #(
parameter RESET_STATE = 1'b1,
parameter RESET_TIME = 100 )
(
output reg reset_out
);
begin
initial begin
reset_out = RESET_STATE;
#RESET_TIME;
reset_out = ~RESET_STATE;
end
end
endmodule
`default_nettype wire
register オプションについては、ツィッターで tu1978 さんと Vengineer さんに教えて頂きました。ありがとうございました。
#pragma HLS INTERFACE ap_none register port=cntin
#pragma HLS INTERFACE ap_none register port=cntout
@E [SIM-345] Cosim only supports the following 'ap_ctrl_none' designs: (1) combinational designs; (2) pipelined design with task inteveral of 1; (3) designs with array streaming or hls_stream or AXI4 stream ports.
@E [SIM-4] *** C/RTL co-simulation finished: FAIL ***
while executing
"cosim_design -trace_level all"
(file "C:/Users/Masaaki/Documents/Vivado_HLS/study/handshake_test/solution1/cosim.tcl" line 8)
、C/RTL コシミュレーション波形が表示された。cd C:/Users/Masaaki/Documents/Vivado_HLS/study/handshake_test/solution1/sim/verilog
current_fileset
open_wave_database handshake_test.wdb
open_wave_config handshake_test.wcfg
//
// handshake_test_tb.cpp
// 2015/05/18
// by marsee
//
#include <stdio.h>
#include <string.h>
#include <ap_int.h>
void handshake_test(ap_int<8> cntin, ap_int<8> *cntout);
int main(){
using namespace std;
ap_int<8> result;
ap_int<8> *cntout;
cntout = &result;
for(int i=0; i<10; i++){
handshake_test((ap_int<8>)i, cntout);
cout << "i = " << i << " " << "result = " << result << endl;
}
return 0;
}
が挿入された。#pragma HLS INTERFACE ap_ctrl_none port=return
//
// handshake_test.cpp
// 2015/05/17
// by marsee
//
#include <stdio.h>
#include <string.h>
#include <ap_int.h>
void handshake_test(ap_int<8> cntin, ap_int<8> *cntout){
#pragma HLS INTERFACE ap_none port=cntin
#pragma HLS INTERFACE ap_none port=cntout
#pragma HLS INTERFACE ap_ctrl_none port=return
*cntout = cntin+1;
}
// ==============================================================
// RTL generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
// Version: 2014.4
// Copyright (C) 2014 Xilinx Inc. All rights reserved.
//
// ===========================================================
`timescale 1 ns / 1 ps
(* CORE_GENERATION_INFO="handshake_test,hls_ip_2014_4,{HLS_INPUT_TYPE=cxx,HLS_INPUT_FLOAT=0,HLS_INPUT_FIXED=1,HLS_INPUT_PART=xc7z010clg400-1,HLS_INPUT_CLOCK=10.000000,HLS_INPUT_ARCH=others,HLS_SYN_CLOCK=1.720000,HLS_SYN_LAT=0,HLS_SYN_TPT=none,HLS_SYN_MEM=0,HLS_SYN_DSP=0,HLS_SYN_FF=0,HLS_SYN_LUT=8}" *)
module handshake_test (
cntin_V,
cntout_V
);
parameter ap_true = 1'b1;
parameter ap_const_lv8_1 = 8'b1;
parameter ap_const_logic_1 = 1'b1;
parameter ap_const_logic_0 = 1'b0;
input [7:0] cntin_V;
output [7:0] cntout_V;
assign cntout_V = (cntin_V + ap_const_lv8_1);
endmodule //handshake_test
//
// handshake_test.cpp
// 2015/05/17
// by marsee
//
#include <stdio.h>
#include <string.h>
#include <ap_int.h>
void handshake_test(ap_int<8> cntin, ap_int<8> *cntout){
*cntout = cntin+1;
}
// ==============================================================
// RTL generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
// Version: 2014.4
// Copyright (C) 2014 Xilinx Inc. All rights reserved.
//
// ===========================================================
`timescale 1 ns / 1 ps
(* CORE_GENERATION_INFO="handshake_test,hls_ip_2014_4,{HLS_INPUT_TYPE=cxx,HLS_INPUT_FLOAT=0,HLS_INPUT_FIXED=1,HLS_INPUT_PART=xc7z010clg400-1,HLS_INPUT_CLOCK=10.000000,HLS_INPUT_ARCH=others,HLS_SYN_CLOCK=1.720000,HLS_SYN_LAT=0,HLS_SYN_TPT=none,HLS_SYN_MEM=0,HLS_SYN_DSP=0,HLS_SYN_FF=0,HLS_SYN_LUT=8}" *)
module handshake_test (
ap_start,
ap_done,
ap_idle,
ap_ready,
cntin_V,
cntout_V,
cntout_V_ap_vld
);
parameter ap_const_logic_1 = 1'b1;
parameter ap_const_logic_0 = 1'b0;
parameter ap_const_lv8_1 = 8'b1;
parameter ap_true = 1'b1;
input ap_start;
output ap_done;
output ap_idle;
output ap_ready;
input [7:0] cntin_V;
output [7:0] cntout_V;
output cntout_V_ap_vld;
reg cntout_V_ap_vld;
/// cntout_V_ap_vld assign process. ///
always @ (ap_start)
begin
if (~(ap_start == ap_const_logic_0)) begin
cntout_V_ap_vld = ap_const_logic_1;
end else begin
cntout_V_ap_vld = ap_const_logic_0;
end
end
assign ap_done = ap_start;
assign ap_idle = ap_const_logic_1;
assign ap_ready = ap_start;
assign cntout_V = (cntin_V + ap_const_lv8_1);
endmodule //handshake_test
module handshake_test (
ap_clk,
ap_rst,
ap_start,
ap_done,
ap_idle,
ap_ready,
cntin_V,
cntout_V,
cntout_V_ap_vld
);
cd C:/Users/Masaaki/Documents/Vivado_HLS/ZYBO/axis_switcher_2014_4/solution1/sim/verilog
current_fileset
open_wave_database axis_switcher.wdb
open_wave_config axis_switcher.wcfg
// BUS_AXI4LS
// 0x00 : Control signals
// bit 0 - ap_start (Read/Write/COH)
// bit 1 - ap_done (Read/COR)
// bit 2 - ap_idle (Read)
// bit 3 - ap_ready (Read)
// bit 7 - auto_restart (Read/Write)
// others - reserved
// 0x04 : Global Interrupt Enable Register
// bit 0 - Global Interrupt Enable (Read/Write)
// others - reserved
// 0x08 : IP Interrupt Enable Register (Read/Write)
// bit 0 - Channel 0 (ap_done)
// bit 1 - Channel 1 (ap_ready)
// others - reserved
// 0x0c : IP Interrupt Status Register (Read/TOW)
// bit 0 - Channel 0 (ap_done)
// bit 1 - Channel 1 (ap_ready)
// others - reserved
// 0x10 : Data signal of ap_return
// bit 31~0 - ap_return[31:0] (Read)
// 0x18 : Data signal of select_r
// bit 31~0 - select_r[31:0] (Read/Write)
// 0x1c : reserved
// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)
//
// axis_switcher.cpp
// 2015/05/14
// by marsee
//
#include <stdio.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>
#include "axis_switcher.h"
int axis_switcher(hls::stream<ap_axis<32,1,1,1> >& ins0, hls::stream<ap_axis<32,1,1,1> >& ins1,
hls::stream<ap_axis<32,1,1,1> >& outs, int select) {
#pragma HLS INTERFACE axis port=ins0
#pragma HLS INTERFACE axis port=ins1
#pragma HLS INTERFACE axis port=outs
#pragma HLS INTERFACE s_axilite port=select bundle=BUS_AXI4LS
#pragma HLS INTERFACE s_axilite port=return bundle=BUS_AXI4LS
#pragma HLS INTERFACE ap_none port=select
ap_axis<32,1,1,1> pix;
do { // user が 1になった時にフレームがスタートする
if (select == 0){
ins0 >> pix;
} else{
ins1 >> pix;
}
} while(pix.user == 0);
for (int y=0; y<VERTICAL_PIXEL_WIDTH; y++){
for (int x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
#pragma HLS PIPELINE
if (!(x==0 && y==0)){ // 最初の入力はすでに入力されている
if (select == 0){
ins0 >> pix;
} else{
ins1 >> pix;
}
}
outs << pix; // AXI4-Stream へ出力
}
}
return 1;
}
//
// axis_switcher.h
// 2015/05/14
// by marsee
//
// #define HORIZONTAL_PIXEL_WIDTH 800
// #define VERTICAL_PIXEL_WIDTH 600
#define HORIZONTAL_PIXEL_WIDTH 20
#define VERTICAL_PIXEL_WIDTH 5
#define ALL_PIXEL_VALUE (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)
//
// axis_switcher_tb.cpp
// 2015/05/14
// by marsee
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <iostream>
#include <fstream>
#include <ap_axi_sdata.h>
#include "axis_switcher.h"
int axis_switcher(hls::stream<ap_axis<32,1,1,1> >& ins0, hls::stream<ap_axis<32,1,1,1> >& ins1,
hls::stream<ap_axis<32,1,1,1> >& outs, int select);
#define CLOCK_PERIOD 10
int main() {
using namespace std;
hls::stream<ap_axis<32,1,1,1> > ins0;
hls::stream<ap_axis<32,1,1,1> > ins1;
hls::stream<ap_axis<32,1,1,1> > outs;
ap_axis<32,1,1,1> pix0, pix1;
ap_axis<32,1,1,1> vals;
int m_seq = 1; // M系列の値
int i;
int xor_shift;
int rect_wave;
int select;
for(int i=0; i<5; i++){ // dummy data
pix0.user = 0;
pix0.data = i;
pix1.user = 0;
pix1.data = i;
ins0 << pix0;
ins1 << pix1;
}
// ins0 には M系列、ins1 には、矩形波を入力する
for(int j=0; j < VERTICAL_PIXEL_WIDTH; j++){
for(i=0; i < HORIZONTAL_PIXEL_WIDTH; i++){
xor_shift = (m_seq>>30 & 1) ^ ((m_seq>>2)& 1) ^ ((m_seq>>1) & 1) ^ (m_seq & 1); // (31, 3, 2, 1) 31ビットのM系列
m_seq = ((m_seq<<1) | xor_shift) & 0x7FFFFFFF;
if (((i+j)%CLOCK_PERIOD) < (CLOCK_PERIOD/2))
rect_wave = 0;
else
rect_wave = 1000;
pix0.data = (ap_int<32>)m_seq;
pix1.data = (ap_int<32>)rect_wave;
select = 0; // M 系列
if (j==0 && i==0) { // 最初のデータの時に TUSER を 1 にする
pix0.user = 1;
pix1.user = 1;
} else {
pix0.user = 0;
pix1.user = 0;
}
if (i == HORIZONTAL_PIXEL_WIDTH-1) { // 行の最後でTLASTをアサートする
pix0.last = 1;
pix1.last = 1;
} else {
pix0.last = 0;
pix1.last = 0;
}
ins0 << pix0;
ins1 << pix1;
}
}
axis_switcher(ins0, ins1, outs, select);
cout << endl;
cout << "outs" << endl;
for(int j=0; j < VERTICAL_PIXEL_WIDTH; j++){
for(i=0; i < HORIZONTAL_PIXEL_WIDTH; i++){
outs >> vals;
ap_int<32> val = vals.data;
cout << hex << val << endl;
if (vals.last)
cout << "AXI-Stream is end" << endl;
}
}
// ins0 には M系列、ins1 には、矩形波を入力する
for(int j=0; j < VERTICAL_PIXEL_WIDTH; j++){
for(i=0; i < HORIZONTAL_PIXEL_WIDTH; i++){
xor_shift = (m_seq>>30 & 1) ^ ((m_seq>>2)& 1) ^ ((m_seq>>1) & 1) ^ (m_seq & 1); // (31, 3, 2, 1) 31ビットのM系列
m_seq = ((m_seq<<1) | xor_shift) & 0x7FFFFFFF;
if (((i+j)%CLOCK_PERIOD) < (CLOCK_PERIOD/2))
rect_wave = 0;
else
rect_wave = 1000;
pix0.data = (ap_int<32>)m_seq;
pix1.data = (ap_int<32>)rect_wave;
select = 1; // 矩形波
if (j==0 && i==0) { // 最初のデータの時に TUSER を 1 にする
pix0.user = 1;
pix1.user = 1;
} else {
pix0.user = 0;
pix1.user = 0;
}
if (i == HORIZONTAL_PIXEL_WIDTH-1) { // 行の最後でTLASTをアサートする
pix0.last = 1;
pix1.last = 1;
} else {
pix0.last = 0;
pix1.last = 0;
}
ins0 << pix0;
ins1 << pix1;
}
}
axis_switcher(ins0, ins1, outs, select);
cout << endl;
cout << "outs" << endl;
for(int j=0; j < VERTICAL_PIXEL_WIDTH; j++){
for(i=0; i < HORIZONTAL_PIXEL_WIDTH; i++){
outs >> vals;
ap_int<32> val = vals.data;
cout << hex << val << endl;
if (vals.last)
cout << "AXI-Stream is end" << endl;
}
}
return 0;
}
`default_nettype none
`timescale 100ps / 1ps
// mt9d111_inf_axis_tb.v
// 2015/05/11
//
module mt9d111_inf_axis_tb;
parameter integer C_S_AXI_LITE_ADDR_WIDTH = 9; // Address width of the AXI Lite Interface
parameter integer C_S_AXI_LITE_DATA_WIDTH = 32; // Data width of the AXI Lite Interface
parameter integer C_M_AXIS_DATA_WIDTH = 32; // AXI4 Stream Master Interface
parameter DELAY = 1;
// Inputs
wire ACLK;
wire ARESETN;
wire pclk_from_pll;
wire pclk;
wire href;
wire vsync;
wire [7:0] cam_data;
wire m_axis_tready;
// Outputs
wire xck;
wire standby;
wire pfifo_overflow;
wire pfifo_underflow;
wire [C_M_AXIS_DATA_WIDTH-1:0] m_axis_tdata;
wire [(C_M_AXIS_DATA_WIDTH/8)-1:0] m_axis_tstrb;
wire m_axis_tvalid;
wire m_axis_tlast;
wire m_axis_tuser;
// AXI Lite Write Address Channel
reg s_axi_lite_awvalid = 1'b0;
wire s_axi_lite_awready;
reg [C_S_AXI_LITE_ADDR_WIDTH-1: 0] s_axi_lite_awaddr = 0;
reg [3-1:0] s_axi_lite_awport = 1'b0;
// AXI Lite Write Data Channel
reg s_axi_lite_wvalid =1'b0;
wire s_axi_lite_wready;
reg [C_S_AXI_LITE_DATA_WIDTH-1: 0] s_axi_lite_wdata = 0;
// AXI Lite Write Response Channel
wire [1:0] s_axi_lite_bresp;
wire s_axi_lite_bvalid;
reg s_axi_lite_bready = 1'b0;
// AXI Lite Read Address Channel
reg s_axi_lite_arvalid = 1'b0;
wire s_axi_lite_arready;
reg [C_S_AXI_LITE_ADDR_WIDTH-1: 0] s_axi_lite_araddr = 1'b0;
reg [3-1:0] s_axi_lite_arport = 0;
// AXI Lite Read Data Channel
wire s_axi_lite_rvalid;
reg s_axi_lite_rready = 1'b0;
wire [C_S_AXI_LITE_DATA_WIDTH-1: 0] s_axi_lite_rdata;
wire [1:0] s_axi_lite_rresp;
integer i;
// Instantiate the Unit Under Test (UUT)
mt9d111_inf_axis # (
.C_M_AXIS_DATA_WIDTH(C_M_AXIS_DATA_WIDTH)
) uut (
.s_axi_lite_aclk(ACLK),
.m_axis_aclk(ACLK),
.axi_resetn(ARESETN),
.s_axi_lite_awvalid(s_axi_lite_awvalid),
.s_axi_lite_awready(s_axi_lite_awready),
.s_axi_lite_awaddr(s_axi_lite_awaddr),
//.s_axi_lite_awport(s_axi_lite_awport),
.s_axi_lite_wvalid(s_axi_lite_wvalid),
.s_axi_lite_wready(s_axi_lite_wready),
.s_axi_lite_wdata(s_axi_lite_wdata),
.s_axi_lite_bresp(s_axi_lite_bresp),
.s_axi_lite_bvalid(s_axi_lite_bvalid),
.s_axi_lite_bready(s_axi_lite_bready),
.s_axi_lite_arvalid(s_axi_lite_arvalid),
.s_axi_lite_arready(s_axi_lite_arready),
.s_axi_lite_araddr(s_axi_lite_araddr),
//.s_axi_lite_arport(s_axi_lite_arport),
.s_axi_lite_rvalid(s_axi_lite_rvalid),
.s_axi_lite_rready(s_axi_lite_rready),
.s_axi_lite_rdata(s_axi_lite_rdata),
.s_axi_lite_rresp(s_axi_lite_rresp),
.m_axis_tdata(m_axis_tdata),
.m_axis_tstrb(m_axis_tstrb),
.m_axis_tvalid(m_axis_tvalid),
.m_axis_tready(m_axis_tready),
.m_axis_tlast(m_axis_tlast),
.m_axis_tuser(m_axis_tuser),
.pclk_from_pll(pclk_from_pll),
.pclk(pclk),
.xck(xck),
.href(href),
.vsync(vsync),
.cam_data(cam_data),
.standby(standby),
.pfifo_overflow(pfifo_overflow),
.pfifo_underflow(pfifo_underflow)
);
assign m_axis_tready = 1'b1;
// ACLK のインスタンス
clk_gen #(
.CLK_PERIOD(100), // 10nsec, 100MHz
.CLK_DUTY_CYCLE(0.5),
.CLK_OFFSET(0),
.START_STATE(1'b0)
) ACLKi (
.clk_out(ACLK)
);
// pclk_from_pll のインスタンス
clk_gen #(
.CLK_PERIOD(278), // 27.8nsec, 約36MHz
.CLK_DUTY_CYCLE(0.5),
.CLK_OFFSET(0),
.START_STATE(1'b0)
) pclk_from_pll_i (
.clk_out(pclk_from_pll)
);
// reset_gen のインスタンス
reset_gen #(
.RESET_STATE(1'b0),
.RESET_TIME(1000) // 100nsec
) RESETi (
.reset_out(ARESETN)
);
// MT9D111 モデル
mt9d111_model #(
// .HORIZONTAL_PIXELS(800),
// .VERTICAL_LINES(600),
// .HBLANK_REG(174),
// .VBLANK_REG(16),
.HORIZONTAL_PIXELS(50),
.VERTICAL_LINES(10),
.HBLANK_REG(10),
.VBLANK_REG(5),
.PCLK_DELAY(1)
) mt9d111_model_i (
.xck(xck),
.pclk(pclk),
.href(href),
.vsync(vsync),
.d(cam_data),
.scl(1'b1),
.sda(),
.standby(standby)
);
initial begin
// Initialize Inputs
s_axi_lite_awaddr = 0;
s_axi_lite_awport = 0;
s_axi_lite_wvalid = 0;
s_axi_lite_wdata = 0;
s_axi_lite_wvalid = 0;
s_axi_lite_bready = 0;
s_axi_lite_araddr = 0;
s_axi_lite_arport = 0;
s_axi_lite_arvalid = 0;
s_axi_lite_rready = 0;
// Wait Reset rising edge
@(posedge ARESETN);
for (i=0; i<10; i=i+1) begin
@(posedge ACLK); // 次のクロックへ
#DELAY;
end
// Add stimulus here
@(posedge ACLK); // 次のクロックへ
#DELAY;
AXI_MASTER_WADC1(32'h0000_0000, 32'h1200_0000);
@(posedge ACLK); // 次のクロックへ
#DELAY;
AXI_MASTER_RADC1(32'h0000_0000);
#DELAY;
// @(posedge ACLK); // 次のクロックへ
// #DELAY;
// AXI_MASTER_WADC2(32'h0000_0004, 32'h0000_0001); // one_shot mode
// @(posedge ACLK); // 次のクロックへ
// #DELAY;
// AXI_MASTER_RADC2(32'h0000_0004);
// @(posedge ACLK); // 次のクロックへ
// #DELAY;
// AXI_MASTER_WADC2(32'h0000_0004, 32'h0000_0003); // one_shot trigger
// @(posedge ACLK); // 次のクロックへ
// #DELAY;
// AXI_MASTER_RADC2(32'h0000_0004);
// @(posedge ACLK); // 次のクロックへ
// #DELAY;
// AXI_MASTER_WADC2(32'h0000_0004, 32'h0000_0003); // one_shot trigger
// @(posedge ACLK); // 次のクロックへ
// #DELAY;
// AXI_MASTER_RADC2(32'h0000_0004);
end
// Write Transcation 1
task AXI_MASTER_WADC1;
input [C_S_AXI_LITE_ADDR_WIDTH-1:0] awaddr;
input [C_S_AXI_LITE_DATA_WIDTH-1:0] wdata;
begin
s_axi_lite_awaddr = awaddr;
s_axi_lite_awvalid = 1'b1;
@(posedge ACLK); // 次のクロックへ
#DELAY;
s_axi_lite_awvalid = 1'b0;
s_axi_lite_wdata = wdata;
s_axi_lite_wvalid = 1'b1;
@(posedge ACLK); // 次のクロックへ, s_axi_lite_wready は常に 1
#DELAY;
s_axi_lite_wvalid = 1'b0;
s_axi_lite_bready = 1'b1;
@(posedge ACLK); // 次のクロックへ
#DELAY;
s_axi_lite_bready = 1'b0;
end
endtask
// Write Transcation 2
task AXI_MASTER_WADC2;
input [C_S_AXI_LITE_ADDR_WIDTH-1:0] awaddr;
input [C_S_AXI_LITE_DATA_WIDTH-1:0] wdata;
begin
s_axi_lite_awaddr = awaddr;
s_axi_lite_awvalid = 1'b1;
@(posedge ACLK); // 次のクロックへ
#DELAY;
s_axi_lite_awvalid = 1'b0;
s_axi_lite_wdata = wdata;
s_axi_lite_wvalid = 1'b1;
@(posedge ACLK); // 次のクロックへ, s_axi_lite_wready は常に 1
#DELAY;
s_axi_lite_wvalid = 1'b0;
@(posedge ACLK); // 次のクロックへ
#DELAY;
s_axi_lite_bready = 1'b1;
@(posedge ACLK); // 次のクロックへ
#DELAY;
s_axi_lite_bready = 1'b0;
end
endtask
// Read Transcation 1
task AXI_MASTER_RADC1;
input [31:0] araddr;
begin
s_axi_lite_araddr = araddr;
s_axi_lite_arvalid = 1'b1;
@(posedge ACLK); // 次のクロックへ
#DELAY;
s_axi_lite_araddr = 0;
s_axi_lite_arvalid = 1'b0;
s_axi_lite_rready = 1'b1;
@(posedge ACLK); // 次のクロックへ
#DELAY;
s_axi_lite_rready = 1'b0;
end
endtask
// Read Transcation 2
task AXI_MASTER_RADC2;
input [31:0] araddr;
begin
s_axi_lite_araddr = araddr;
s_axi_lite_arvalid = 1'b1;
@(posedge ACLK); // 次のクロックへ
#DELAY;
s_axi_lite_araddr = 0;
s_axi_lite_arvalid = 1'b0;
@(posedge ACLK); // 次のクロックへ
#DELAY;
s_axi_lite_rready = 1'b1;
@(posedge ACLK); // 次のクロックへ
#DELAY;
s_axi_lite_rready = 1'b0;
end
endtask
endmodule
module clk_gen #(
parameter CLK_PERIOD = 100,
parameter real CLK_DUTY_CYCLE = 0.5,
parameter CLK_OFFSET = 0,
parameter START_STATE = 1'b0 )
(
output reg clk_out
);
begin
initial begin
#CLK_OFFSET;
forever
begin
clk_out = START_STATE;
#(CLK_PERIOD-(CLK_PERIOD*CLK_DUTY_CYCLE)) clk_out = ~START_STATE;
#(CLK_PERIOD*CLK_DUTY_CYCLE);
end
end
end
endmodule
module reset_gen #(
parameter RESET_STATE = 1'b1,
parameter RESET_TIME = 100 )
(
output reg reset_out
);
begin
initial begin
reset_out = RESET_STATE;
#RESET_TIME;
reset_out = ~RESET_STATE;
end
end
endmodule
`default_nettype wire
// mt9d111_model.v
// mt9d111 の動作モデル
// RGB565 を出力
`default_nettype none
`timescale 1ns / 1ps
module mt9d111_model # (
parameter integer HORIZONTAL_PIXELS = 800,
parameter integer VERTICAL_LINES = 600,
parameter integer HBLANK_REG = 174, // pixels
parameter integer VBLANK_REG = 16, // rows
parameter integer PCLK_DELAY = 1
)(
input wire xck,
output reg pclk = 1'b1,
output reg href = 1'b0,
output reg vsync = 1'b1,
output reg [7:0] d = 8'd0,
input wire scl,
inout wire sda,
input wire standby
);
parameter [2:0] FRAME_START_BLANKING = 3'b000,
ACTIVE_DATA_TIME = 3'b001,
HORIZONTAL_BLANKING = 3'b011,
FRAME_END_BLANKING = 3'b010,
VERTICAL_BLANKING = 3'b110;
reg [2:0] mt9d111_cs = VERTICAL_BLANKING;
reg [2:0] fseb_count = 3'd5;
reg [15:0] adt_count = (HORIZONTAL_PIXELS * 2) - 1;
reg [15:0] hb_count = HBLANK_REG - 1;
reg [15:0] fvt_count = VERTICAL_LINES - 1;
reg [31:0] vb_count = VBLANK_REG * (HORIZONTAL_PIXELS + HBLANK_REG) - 1;
reg href_node = 1'b0;
reg vsync_node = 1'b0;
reg dout_is_even = 1'b0;
// R, G, B 毎に違った生成多項式のM系列を用意した
function [7:0] mseqf8_R (input [7:0] din);
reg xor_result;
begin
xor_result = din[7] ^ din[3] ^ din[2] ^ din[1];
mseqf8_R = {din[6:0], xor_result};
end
endfunction
function [7:0] mseqf8_G (input [7:0] din);
reg xor_result;
begin
xor_result = din[7] ^ din[4] ^ din[2] ^ din[0];
mseqf8_G = {din[6:0], xor_result};
end
endfunction
function [7:0] mseqf8_B (input [7:0] din);
reg xor_result;
begin
xor_result = din[7] ^ din[5] ^ din[2] ^ din[1];
mseqf8_B = {din[6:0], xor_result};
end
endfunction
reg [7:0] mseq8r = 8'd1;
reg [7:0] mseq8g = 8'd1;
reg [7:0] mseq8b = 8'd1;
// pclk の出力
always @*
pclk <= #PCLK_DELAY xck;
// MT9D111 のステート
always @(posedge pclk) begin
case (mt9d111_cs)
FRAME_START_BLANKING : begin
if (fseb_count==0) begin
mt9d111_cs <= ACTIVE_DATA_TIME;
href_node <= 1'b1;
end
end
ACTIVE_DATA_TIME : begin
if (adt_count==0) begin
if (fvt_count==0) // frame end
mt9d111_cs <= FRAME_END_BLANKING;
else
mt9d111_cs <= HORIZONTAL_BLANKING;
href_node <= 1'b0;
end
end
HORIZONTAL_BLANKING : begin
if (hb_count==0) begin
mt9d111_cs <= ACTIVE_DATA_TIME;
href_node <= 1'b1;
end
end
FRAME_END_BLANKING : begin
if (fseb_count==0) begin
mt9d111_cs <= VERTICAL_BLANKING;
vsync_node <= 1'b0;
end
end
VERTICAL_BLANKING : begin
if (vb_count==0) begin
mt9d111_cs <= FRAME_START_BLANKING;
vsync_node <= 1'b1;
end
end
endcase
end
// vsync, href 出力、レーシングを防ぐためにpclk よりも出力を遅らせる
always @* begin
vsync <= #1 vsync_node;
href <= #1 href_node;
end
// Frame Start/End Blanking Counter (6 pixel clocks)
always @(posedge pclk) begin
if (mt9d111_cs==FRAME_START_BLANKING || mt9d111_cs==FRAME_END_BLANKING) begin
if (fseb_count > 0)
fseb_count <= fseb_count - 3'd1;
end else
fseb_count <= 3'd5;
end
// Active Data Time Counter
always @(posedge pclk) begin
if (mt9d111_cs==ACTIVE_DATA_TIME) begin
if (adt_count > 0)
adt_count <= adt_count - 16'd1;
end else
adt_count <= (HORIZONTAL_PIXELS * 2) - 1;
end
// Horizontal Blanking Counter
always @(posedge pclk) begin
if (mt9d111_cs==HORIZONTAL_BLANKING) begin
if (hb_count > 0)
hb_count <= hb_count - 16'd1;
end else
hb_count <= HBLANK_REG - 1;
end
// Frame Valid Time Counter
always @(posedge pclk) begin
if (mt9d111_cs==ACTIVE_DATA_TIME && adt_count==0)
fvt_count <= fvt_count - 16'd1;
else if (mt9d111_cs==FRAME_END_BLANKING)
fvt_count <= VERTICAL_LINES - 1;
end
// Vertical Blanking Counter
always @(posedge pclk) begin
if (mt9d111_cs==VERTICAL_BLANKING) begin
if (vb_count > 0)
vb_count <= vb_count - 32'd1;
end else
vb_count <= VBLANK_REG * (HORIZONTAL_PIXELS + HBLANK_REG) - 1;
end
// Red のM系列符号生成
always @(posedge pclk) begin
// if (mt9d111_cs==ACTIVE_DATA_TIME)
mseq8r <= mseqf8_R(mseq8r);
end
// Green のM系列符号生成
always @(posedge pclk) begin
// if (mt9d111_cs==ACTIVE_DATA_TIME)
mseq8g <= mseqf8_G(mseq8g);
end
// Blue のM系列符号生成
always @(posedge pclk) begin
// if (mt9d111_cs==ACTIVE_DATA_TIME)
mseq8b <= mseqf8_B(mseq8b);
end
// d 出力のODD とEVEN を示す
always @(posedge pclk) begin
if (mt9d111_cs==ACTIVE_DATA_TIME)
dout_is_even <= ~dout_is_even;
else
dout_is_even <= 1'b0;
end
// d 出力、レーシングを防ぐためにpclk よりも出力を遅らせる
always @(posedge pclk) begin
if (mt9d111_cs==ACTIVE_DATA_TIME) begin
if (dout_is_even)
d <= #1 {mseq8g[4:2], mseq8b[7:3]};
else
d <= #1 {mseq8r[7:3], mseq8g[7:5]};
end
end
endmodule
`default_nettype wire
-------------------------------------------------------------------------------
--
-- AXI Stream
--
-- VHDL-Standard: VHDL'93
----------------------------------------------------------------------------
--
-- Structure:
-- mt9d111_inf_axims
--
----------------------------------------------------------------------------
--
-- 2014/11/07 : AXI4 Lite Slave を追加
-- 2014/11/08 : one_shot_reg を実装。
-- オフセット0番地: フレーム・バッファの先頭アドレス(fb_start_address)
-- オフセット4番地: 0 ビット目が 0 の時動画、0 ビット目に 1 の時に、ワンショットで取得した1フレームのカメラ画像を表示(one_shot_reg)
-- 1 ビット目に 1 を Write した時に、ワンショットで1フレームの画像をフレーム・バッファに保存
-- 2015/05/09 : AXI4 Master から AXI4 Master Stream にインターフェースを変更、generic map, port map は ar37425\axi_stream_v1_00_a\hdl\vhdl の axi_stream.vhd から引用した
-- AXI4 Stream なので、fb_start_address は使用しない。そこに書き込まれたというスタート信号だけを使用する
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_misc.all;
--library unisim;
--use unisim.vcomponents.all;
entity mt9d111_inf_axis is
generic(
-- AXI4 Lite Slave Interface
C_S_AXI_LITE_ADDR_WIDTH : integer := 9; -- Address width of the AXI Lite Interface
C_S_AXI_LITE_DATA_WIDTH : integer := 32; -- Data width of the AXI Lite Interface
-- AXI4 Stream Master Interface
C_M_AXIS_DATA_WIDTH : integer range 32 to 256 := 32 -- Master AXI Stream Data Width
);
port (
-- Global Ports
s_axi_lite_aclk : in std_logic;
m_axis_aclk : in std_logic;
axi_resetn : in std_logic;
-- Master Stream Ports
-- m_axis_aresetn : out std_logic;
m_axis_tdata : out std_logic_vector(C_M_AXIS_DATA_WIDTH-1 downto 0);
m_axis_tstrb : out std_logic_vector((C_M_AXIS_DATA_WIDTH/8)-1 downto 0);
m_axis_tvalid : out std_logic;
m_axis_tready : in std_logic;
m_axis_tlast : out std_logic;
m_axis_tuser : out std_logic_vector(0 downto 0);
-- AXI Lite Slave Ports
s_axi_lite_awvalid : in std_logic;
s_axi_lite_awready : out std_logic;
s_axi_lite_awaddr : in std_logic_vector(C_S_AXI_LITE_ADDR_WIDTH-1 downto 0);
-- AXI Lite Write Data Channel --
s_axi_lite_wvalid : in std_logic;
s_axi_lite_wready : out std_logic;
s_axi_lite_wdata : in std_logic_vector(C_S_AXI_LITE_DATA_WIDTH-1 downto 0);
-- AXI Lite Write Response Channel --
s_axi_lite_bresp : out std_logic_vector(1 downto 0);
s_axi_lite_bvalid : out std_logic;
s_axi_lite_bready : in std_logic;
-- AXI Lite Read Address Channel --
s_axi_lite_arvalid : in std_logic;
s_axi_lite_arready : out std_logic;
s_axi_lite_araddr : in std_logic_vector(C_S_AXI_LITE_ADDR_WIDTH-1 downto 0);
-- AXI Lite Read Data Channel --
s_axi_lite_rvalid : out std_logic;
s_axi_lite_rready : in std_logic;
s_axi_lite_rdata : out std_logic_vector(C_S_AXI_LITE_DATA_WIDTH-1 downto 0);
s_axi_lite_rresp : out std_logic_vector(1 downto 0);
-- MT9D111 Camera Interface
pclk_from_pll : in std_logic; -- PLLからMT9D111のxck に出力するクロック
pclk : in std_logic; -- MT9D111からのピクセルクロック入力
xck : out std_logic; -- MT9D111へのピクセルクロック出力
href : in std_logic;
vsync : in std_logic;
cam_data : in std_logic_vector(7 downto 0);
standby : out std_logic; -- STANDBY出力(ディスエーブル、0固定)
pfifo_overflow : out std_logic; -- pfifo overflow
pfifo_underflow : out std_logic -- pfifo underflow
);
end mt9d111_inf_axis;
-------------------------------------------------------------------------------
-- Architecture
-------------------------------------------------------------------------------
architecture implementation of mt9d111_inf_axis is
constant ONE_SHOT_PULSE_LENGTH : integer := 20; -- 1ショットパルスの長さのAXI Lite Slave ACLKのクロック数をセット
signal reset_1d, reset_2d, reset : std_logic;
signal preset_1d, preset_2d, preset : std_logic;
signal pfifo_empty : std_logic;
signal pfifo_almost_empty : std_logic;
signal pfifo_rd_data_count : std_logic_vector(9 downto 0);
signal pfifo_rd_dcount_dec : unsigned(9 downto 0);
signal pfifo_rd_en : std_logic;
signal ACLK : std_logic := '0';
signal one_shot_state : std_logic;
signal one_shot_trigger : std_logic;
signal init_done : std_logic;
signal pfifo_dout : std_logic_vector(33 downto 0);
component mt9d111_cam_cont
port(
aclk : in std_logic;
areset : in std_logic;
pclk : in std_logic;
preset : in std_logic;
pclk_from_pll : in std_logic;
xclk : out std_logic;
line_valid : in std_logic;
frame_valid : in std_logic;
cam_data : in std_logic_vector(7 downto 0);
standby : out std_logic;
pfifo_rd_en : in std_logic;
pfifo_dout : out std_logic_vector(33 downto 0); -- frame data start signal + data[31:0]
pfifo_empty : out std_logic;
pfifo_almost_empty : out std_logic;
pfifo_rd_data_count : out std_logic_vector(9 downto 0);
pfifo_overflow : out std_logic;
pfifo_underflow : out std_logic;
one_shot_state : in std_logic; -- 1フレーム分取り込んだカメラ画像を保持する
one_shot_trigger : in std_logic -- 1フレーム分のカメラ画像取り込みのトリガー、1クロックパルス
);
end component;
component mt9d111_axi_lite_slave generic (
C_S_AXI_LITE_ADDR_WIDTH : integer range 9 to 9 := 9; -- Address width of the AXI Lite Interface
C_S_AXI_LITE_DATA_WIDTH : integer range 32 to 32 := 32; -- Data width of the AXI Lite Interface
C_DISPLAY_START_ADDRESS : std_logic_vector(31 downto 0) := x"1A000000";
ONE_SHOT_PULSE_LENGTH : integer := 20 -- 1ショットパルスの長さのAXI Lite Slave ACLKのクロック数をセット
);
port(
-- Clock and Reset
s_axi_lite_aclk : in std_logic;
axi_resetn : in std_logic;
-------------------------------
-- AXI4 Lite Slave Interface --
-------------------------------
-- AXI Lite Write Address Channel --
s_axi_lite_awvalid : in std_logic;
s_axi_lite_awready : out std_logic;
s_axi_lite_awaddr : in std_logic_vector(C_S_AXI_LITE_ADDR_WIDTH-1 downto 0);
-- AXI Lite Write Data Channel --
s_axi_lite_wvalid : in std_logic;
s_axi_lite_wready : out std_logic;
s_axi_lite_wdata : in std_logic_vector(C_S_AXI_LITE_DATA_WIDTH-1 downto 0);
-- AXI Lite Write Response Channel --
s_axi_lite_bresp : out std_logic_vector(1 downto 0);
s_axi_lite_bvalid : out std_logic;
s_axi_lite_bready : in std_logic;
-- AXI Lite Read Address Channel --
s_axi_lite_arvalid : in std_logic;
s_axi_lite_arready : out std_logic;
s_axi_lite_araddr : in std_logic_vector(C_S_AXI_LITE_ADDR_WIDTH-1 downto 0);
-- AXI Lite Read Data Channel
s_axi_lite_rvalid : out std_logic;
s_axi_lite_rready : in std_logic;
s_axi_lite_rdata : out std_logic_vector(C_S_AXI_LITE_DATA_WIDTH-1 downto 0);
s_axi_lite_rresp : out std_logic_vector(1 downto 0);
fb_start_address : out std_logic_vector(31 downto 0); -- Frame Buffer のスタートアドレス
init_done : out std_logic; -- fb_start_address に書き込まれた
one_shot_state : out std_logic; -- 1フレーム分取り込んだカメラ画像を保持する
one_shot_trigger : out std_logic -- 1フレーム分のカメラ画像取り込みのトリガー、1クロックパルス
);
end component;
begin
ACLK <= m_axis_aclk;
-- mt9d111_axi_lite_slave のインスタンス
mt9d111_axi_lite_slave_i : mt9d111_axi_lite_slave generic map(
C_S_AXI_LITE_ADDR_WIDTH => C_S_AXI_LITE_ADDR_WIDTH,
C_S_AXI_LITE_DATA_WIDTH => C_S_AXI_LITE_DATA_WIDTH,
C_DISPLAY_START_ADDRESS => (others => '0'),
ONE_SHOT_PULSE_LENGTH => ONE_SHOT_PULSE_LENGTH
) port map (
s_axi_lite_aclk => s_axi_lite_aclk,
axi_resetn => axi_resetn,
s_axi_lite_awvalid => s_axi_lite_awvalid,
s_axi_lite_awready => s_axi_lite_awready,
s_axi_lite_awaddr => s_axi_lite_awaddr,
s_axi_lite_wvalid => s_axi_lite_wvalid,
s_axi_lite_wready => s_axi_lite_wready,
s_axi_lite_wdata => s_axi_lite_wdata,
s_axi_lite_bresp => s_axi_lite_bresp,
s_axi_lite_bvalid => s_axi_lite_bvalid,
s_axi_lite_bready => s_axi_lite_bready,
s_axi_lite_arvalid => s_axi_lite_arvalid,
s_axi_lite_arready => s_axi_lite_arready,
s_axi_lite_araddr => s_axi_lite_araddr,
s_axi_lite_rvalid => s_axi_lite_rvalid,
s_axi_lite_rready => s_axi_lite_rready,
s_axi_lite_rdata => s_axi_lite_rdata,
s_axi_lite_rresp => s_axi_lite_rresp,
fb_start_address => open,
init_done => init_done,
one_shot_state => one_shot_state,
one_shot_trigger => one_shot_trigger
);
-- axi_resetn をACLK で同期化
process (ACLK) begin
if ACLK'event and ACLK='1' then
reset_1d <= not axi_resetn or not init_done;
reset_2d <= reset_1d;
end if;
end process;
reset <= reset_2d;
-- axi_resetn をpclk で同期化
process(pclk) begin
if pclk'event and pclk='1' then
preset_1d <= not axi_resetn or not init_done;
preset_2d <= preset_1d;
end if;
end process;
preset <= preset_2d;
pfifo_rd_en <= not pfifo_empty and m_axis_tready;
mt9d111_cam_cont_i : mt9d111_cam_cont port map(
aclk => ACLK,
areset => reset,
pclk => pclk,
preset => preset,
pclk_from_pll => pclk_from_pll,
xclk => xck,
line_valid => href,
frame_valid => vsync,
cam_data => cam_data,
standby => standby,
pfifo_rd_en => pfifo_rd_en,
pfifo_dout => pfifo_dout, -- frame start data signal + tlast + data[31:0]
pfifo_empty => pfifo_empty,
pfifo_almost_empty => pfifo_almost_empty,
pfifo_rd_data_count => pfifo_rd_data_count,
pfifo_overflow => pfifo_overflow,
pfifo_underflow => pfifo_underflow,
one_shot_state => one_shot_state,
one_shot_trigger => one_shot_trigger
);
m_axis_tdata <= pfifo_dout(31 downto 0);
m_axis_tuser(0) <= pfifo_dout(32);
m_axis_tlast <= pfifo_dout(33);
m_axis_tvalid <= not pfifo_empty;
pfifo_rd_en <= not pfifo_empty and m_axis_tready;
m_axis_tstrb <= (others => '1');
end implementation;
// mt9d111_axi_lite_slave.v
// mt9d111_inf_axi_master のAXI Lite Slave モジュール。Frame Buffer のスタートアドレス・レジスタを持つ。
//
// 2014/11/08 : one_shot_reg を実装。
// オフセット0番地: フレーム・バッファの先頭アドレス(fb_start_address)
// オフセット4番地: 0 ビット目が 0 の時動画、0 ビット目に 1 の時に、ワンショットで取得した1フレームのカメラ画像を表示(one_shot_reg)
// 1 ビット目に 1 を Write した時に、ワンショットで1フレームの画像をフレーム・バッファに保存
// 2014/11/11 : init_done を追加
//
`default_nettype none
module mt9d111_axi_lite_slave # (
parameter integer C_S_AXI_LITE_ADDR_WIDTH = 9, // Address width of the AXI Lite Interface
parameter integer C_S_AXI_LITE_DATA_WIDTH = 32, // Data width of the AXI Lite Interface
parameter [31:0] C_DISPLAY_START_ADDRESS = 32'h1A00_0000,
parameter integer ONE_SHOT_PULSE_LENGTH = 20 // 1ショットパルスの長さのAXI Lite Slave ACLKのクロック数をセット
)(
input wire s_axi_lite_aclk,
input wire axi_resetn,
// AXI Lite Write Address Channel
input wire s_axi_lite_awvalid,
output wire s_axi_lite_awready,
input wire [C_S_AXI_LITE_ADDR_WIDTH-1: 0] s_axi_lite_awaddr,
// AXI Lite Write Data Channel
input wire s_axi_lite_wvalid,
output wire s_axi_lite_wready,
input wire [C_S_AXI_LITE_DATA_WIDTH-1: 0] s_axi_lite_wdata,
// AXI Lite Write Response Channel
output wire [1:0] s_axi_lite_bresp,
output wire s_axi_lite_bvalid,
input wire s_axi_lite_bready,
// AXI Lite Read Address Channel
input wire s_axi_lite_arvalid,
output wire s_axi_lite_arready,
input wire [C_S_AXI_LITE_ADDR_WIDTH-1: 0] s_axi_lite_araddr,
// AXI Lite Read Data Channel
output wire s_axi_lite_rvalid,
input wire s_axi_lite_rready,
output reg [C_S_AXI_LITE_DATA_WIDTH-1: 0] s_axi_lite_rdata,
output wire [1:0] s_axi_lite_rresp,
output wire [31:0] fb_start_address, // Frame Buffer のスタートアドレス
output reg init_done, // fb_start_address に書き込まれた
output wire one_shot_state, // 1フレーム分取り込んだカメラ画像を保持する
output reg one_shot_trigger // 1フレーム分のカメラ画像取り込みのトリガー、1クロックパルス
);
// RESP の値の定義
parameter RESP_OKAY = 2'b00;
parameter RESP_EXOKAY = 2'b01;
parameter RESP_SLVERR = 2'b10;
parameter RESP_DECERR = 2'b11;
parameter [1:0] IDLE_WR = 2'b00, // for wrt_cs
DATA_WRITE_HOLD = 2'b01,
BREADY_ASSERT = 2'b11;
parameter IDLE_RD = 1'b0, // for rdt_cs
AR_DATA_WAIT = 1'b1;
reg [1:0] wrt_cs = IDLE_WR;
reg [31:0] fb_start_addr_reg = C_DISPLAY_START_ADDRESS;
reg rdt_cs = IDLE_RD;
reg reset_1d = 1'b0;
reg reset = 1'b0;
reg awready = 1'b1;
reg bvalid = 1'b0;
reg arready = 1'b1;
reg rvalid = 1'b0;
wire aclk;
reg [31:0] one_shot_reg;
parameter [1:0] IDLE_TSM = 2'b00, // for one_shot_tsm
WAIT_ONE_SHOT = 2'b01,
ONE_SHOT_TRIG = 2'b11;
reg [1:0] one_shot_tsm;
integer one_shot_counter;
assign aclk = s_axi_lite_aclk;
// Synchronization of axi_resetn
always @(posedge aclk) begin
reset_1d <= ~axi_resetn;
reset <= reset_1d;
end
// AXI4 Lite Slave Write Transaction State Machine
always @(posedge aclk) begin
if (reset) begin
wrt_cs <= IDLE_WR;
awready <= 1'b1;
bvalid <= 1'b0;
end else begin
case (wrt_cs)
IDLE_WR :
if (s_axi_lite_awvalid & ~s_axi_lite_wvalid) begin // Write Transaction Start
wrt_cs <= DATA_WRITE_HOLD;
awready <= 1'b0;
end else if (s_axi_lite_awvalid & s_axi_lite_wvalid) begin // Write Transaction Start with data
wrt_cs <= BREADY_ASSERT;
awready <= 1'b0;
bvalid <= 1'b1;
end
DATA_WRITE_HOLD :
if (s_axi_lite_wvalid) begin // Write data just valid
wrt_cs <= BREADY_ASSERT;
bvalid <= 1'b1;
end
BREADY_ASSERT :
if (s_axi_lite_bready) begin // The write transaction was terminated.
wrt_cs <= IDLE_WR;
bvalid <= 1'b0;
awready <= 1'b1;
end
endcase
end
end
assign s_axi_lite_awready = awready;
assign s_axi_lite_bvalid = bvalid;
assign s_axi_lite_wready = 1'b1;
assign s_axi_lite_bresp = RESP_OKAY;
// AXI4 Lite Slave Read Transaction State Machine
always @(posedge aclk) begin
if (reset) begin
rdt_cs <= IDLE_RD;
arready <= 1'b1;
rvalid <= 1'b0;
end else begin
case (rdt_cs)
IDLE_RD :
if (s_axi_lite_arvalid) begin
rdt_cs <= AR_DATA_WAIT;
arready <= 1'b0;
rvalid <= 1'b1;
end
AR_DATA_WAIT :
if (s_axi_lite_rready) begin
rdt_cs <= IDLE_RD;
arready <= 1'b1;
rvalid <= 1'b0;
end
endcase
end
end
assign s_axi_lite_arready = arready;
assign s_axi_lite_rvalid = rvalid;
assign s_axi_lite_rresp = RESP_OKAY;
// fb_start_addr_reg
always @(posedge aclk) begin
if (reset) begin
init_done <= 1'b0;
fb_start_addr_reg <= C_DISPLAY_START_ADDRESS;
end else begin
if (s_axi_lite_wvalid==1'b1 && s_axi_lite_awaddr[2]==1'b0) begin
init_done <= 1'b1;
fb_start_addr_reg <= s_axi_lite_wdata;
end
end
end
assign fb_start_address = fb_start_addr_reg;
// one_shot_reg
always @(posedge aclk) begin
if (reset)
one_shot_reg <= 32'd0; // default is continuous display mode
else
if (s_axi_lite_wvalid==1'b1 && s_axi_lite_awaddr[2]==1'b1)
one_shot_reg <= s_axi_lite_wdata;
end
assign one_shot_state = one_shot_reg[0];
// one_shot_tsm(State Machine for one_shot_trgger)
always @(posedge aclk) begin
if (reset) begin
one_shot_tsm <= IDLE_TSM;
one_shot_trigger <= 1'b0;
end else begin
case (one_shot_tsm)
IDLE_TSM :
if (s_axi_lite_awvalid & awready & s_axi_lite_awaddr[2]) begin // one_shot_reg address
if (s_axi_lite_wvalid) begin // s_axi_wready is always 1
if (s_axi_lite_wdata[1]) begin // one_shot was triggered
one_shot_tsm <= ONE_SHOT_TRIG;
one_shot_trigger <= 1'b1;
end else begin // is not trigger
one_shot_tsm <= IDLE_TSM;
one_shot_trigger <= 1'b0;
end
end else begin // s_axi_lite_wvalid is not asserted
one_shot_tsm <= WAIT_ONE_SHOT;
one_shot_trigger <= 1'b0;
end
end
WAIT_ONE_SHOT :
if (s_axi_lite_wvalid) begin // s_axi_wready is always 1
if (s_axi_lite_wdata[1]) begin // one_shot was triggered
one_shot_tsm <= ONE_SHOT_TRIG;
one_shot_trigger <= 1'b1;
end else begin // is not trigger
one_shot_tsm <= IDLE_TSM;
one_shot_trigger <= 1'b0;
end
end
ONE_SHOT_TRIG : begin
if (one_shot_counter == 0) begin
one_shot_tsm <= IDLE_TSM;
one_shot_trigger <= 1'b0;
end
end
endcase
end
end
// one shot pulse length counter
always @(posedge aclk) begin
if (reset) begin
one_shot_counter <= ONE_SHOT_PULSE_LENGTH;
end else if (one_shot_tsm == ONE_SHOT_TRIG) begin
one_shot_counter <= one_shot_counter - 1;
end else begin
one_shot_counter <= ONE_SHOT_PULSE_LENGTH;
end
end
// s_axi_lite_rdata
always @(posedge aclk) begin
if (reset) begin
s_axi_lite_rdata <= 0;
end else if (s_axi_lite_arvalid) begin
case (s_axi_lite_araddr[2])
1'b0 : s_axi_lite_rdata <= fb_start_addr_reg;
1'b1 : s_axi_lite_rdata <= one_shot_reg;
endcase
end
end
endmodule
`default_nettype wire
// MT9D111カメラコントローラ
// mt9d111_cam_cont.v
// 2012/12/26
//
// 2014/11/07 : fb_start_address を追加。レジスタに設定された値をスタートアドレスとして参照。
// 2014/11/08 : one_shot_state, one_shot_trigger の入力ポートを追加
// 2015/05/09 : UPSIDE_DOWN を削除、pifo_dout を 64ビット長から 32 ビット長へ変更、paddr を削除
// 2015/05/11 : last_pixel_4_line を出力するために、データを1つ遅らせることで、line_valid の falling edge を検出し、last_pixel_4_line とする。fb_start_addresを削除
`default_nettype none
module mt9d111_cam_cont (
input wire aclk,
input wire areset,
input wire pclk,
input wire preset,
input wire pclk_from_pll,
output wire xclk,
input wire line_valid,
input wire frame_valid,
input wire [7:0] cam_data,
output wire standby,
input wire pfifo_rd_en,
output wire [33:0] pfifo_dout,
output wire pfifo_empty,
output wire pfifo_almost_empty,
output wire [9:0] pfifo_rd_data_count,
output wire pfifo_overflow,
output wire pfifo_underflow,
input wire one_shot_state, // 1フレーム分取り込んだカメラ画像を保持する
input wire one_shot_trigger // 1フレーム分のカメラ画像取り込みのトリガー、1クロックパルス
);
`include "./disp_timing_parameters.vh"
// Frame Buffer End Address
reg line_valid_1d, line_valid_2d;
reg frame_valid_1d, frame_valid_2d;
reg [7:0] cam_data_1d;
reg line_valid_1d_odd;
reg line_v_1d_odd_1d, line_v_1d_odd_2d;
reg [31:0] rgb565, rgb565_1d;
wire pfifo_full, pfifo_almost_full;
parameter [1:0] IDLE_ADDR_RST = 2'b00,
ADDR_RST = 2'b01,
ADDR_RST_HOLD = 2'b11;
parameter [2:0] IDLE_OS = 3'b000,
WAIT_FRAME_VALID_END = 3'b001,
HOLD_PICTURE = 3'b011,
WAIT_FRAME_VALID_LOW = 3'b010,
WAIT_FRAME_VALID_HIGH = 3'b110;
reg [2:0] one_shot_sm;
reg frame_valid_1d_oh;
reg ost_1d, ost_2d, ost_3d, ost_4d;
reg one_shot_tig_pclk;
reg first_pixel;
reg last_pixel_4_line;
reg one_shot_state_1d, one_shot_state_2d;
assign standby = 1'b0;
// MT9D111 へのクロックを出力 (xclk)
ODDR #(
.DDR_CLK_EDGE("SAME_EDGE"), // "OPPOSITE_EDGE" or "SAME_EDGE"
.INIT(1'b0), // Initial value of Q: 1'b0 or 1'b1
.SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC"
) ODDR_inst (
.Q(xclk), // 1-bit DDR output
.C(pclk_from_pll), // 1-bit clock input
.CE(1'b1), // 1-bit clock enable input
.D1(1'b1), // 1-bit data input (positive edge)
.D2(1'b0), // 1-bit data input (negative edge)
.R(1'b0), // 1-bit reset
.S(1'b0) // 1-bit set
);
// 入力信号を一旦ラッチする
always @(posedge pclk) begin
if (preset) begin
line_valid_1d <= 1'b0;
line_valid_2d <= 1'b0;
frame_valid_1d <= 1'b0;
frame_valid_2d <= 1'b0;
cam_data_1d <= 8'd0;
end else begin
line_valid_1d <= line_valid;
line_valid_2d <= line_valid_1d;
frame_valid_1d <= frame_valid;
frame_valid_2d <= frame_valid_1d;
cam_data_1d <= cam_data;
end
end
// one_shot_state を pclk で同期化する
always @(posedge pclk) begin
if (preset) begin
one_shot_state_1d <= 1'b0;
one_shot_state_2d <= 1'b0;
end else begin
one_shot_state_1d <= one_shot_state;
one_shot_state_2d <= one_shot_state_1d;
end
end
// one_shot_trigger はAXIバスのaclkで生成されているので、pclkで動作するステートマシンでは、本当にone shotでは取れない
// よって、one shotと言ってもある程度の幅を用意してある。pclk の幅のone shot pulse を作る必要がある
always @(posedge pclk) begin // one_shot_trigger を pclk で同期化
if (preset) begin
ost_1d <= 1'b0;
ost_2d <= 1'b0;
ost_3d <= 1'b0;
ost_4d <= 1'b0;
end else begin
ost_1d <= one_shot_trigger;
ost_2d <= ost_1d;
ost_3d <= ost_2d;
ost_4d <= ost_3d;
end
end
// pclk 幅の one shot pulse を生成
always @(posedge pclk) begin
if (preset) begin
one_shot_tig_pclk <= 1'b0;
end else if (ost_3d==1'b1 && ost_4d==1'b0) begin // rising edge
one_shot_tig_pclk <= 1'b1;
end else begin
one_shot_tig_pclk <= 1'b0;
end
end
// one shot state machine
// frame_valid_1d_oh を生成する
always @(posedge pclk) begin
if (preset) begin
one_shot_sm <= IDLE_OS;
frame_valid_1d_oh <= frame_valid_1d;
end else begin
case (one_shot_sm)
IDLE_OS : begin
frame_valid_1d_oh <= frame_valid_1d;
if (one_shot_state_2d) begin
one_shot_sm <= WAIT_FRAME_VALID_END;
end
end
WAIT_FRAME_VALID_END : begin
frame_valid_1d_oh <= frame_valid_1d;
if (!frame_valid_1d) begin
one_shot_sm <= HOLD_PICTURE;
end
end
HOLD_PICTURE : begin
frame_valid_1d_oh <= 1'b0;
if (one_shot_tig_pclk) begin
one_shot_sm <= WAIT_FRAME_VALID_LOW;
end else if (~one_shot_state_2d & ~frame_valid_1d) begin
one_shot_sm <= IDLE_OS;
end
end
WAIT_FRAME_VALID_LOW : begin
frame_valid_1d_oh <= 1'b0;
if (!frame_valid_1d) begin
one_shot_sm <= WAIT_FRAME_VALID_HIGH;
end
end
WAIT_FRAME_VALID_HIGH : begin
frame_valid_1d_oh <= frame_valid_1d;
if (frame_valid_1d) begin
one_shot_sm <= WAIT_FRAME_VALID_END;
end
end
endcase
end
end
// line_valid_1d が偶数か奇数かをカウント
always @(posedge pclk) begin
if (preset)
line_valid_1d_odd <= 1'b0;
else begin
if (!frame_valid_1d_oh)
line_valid_1d_odd <= 1'b0;
else if (line_valid_1d)
line_valid_1d_odd <= ~line_valid_1d_odd;
else
line_valid_1d_odd <= 1'b0;
end
end
// rgb565でラッチしているので、line_valid_1d_odd を1クロック遅延する
always @(posedge pclk) begin
if (preset) begin
line_v_1d_odd_1d <= 1'b0;
line_v_1d_odd_2d <= 1'b0;
end else begin
line_v_1d_odd_1d <= line_valid_1d_odd;
line_v_1d_odd_2d <= line_v_1d_odd_1d;
end
end
// RGB565 のデータを保存する。正常と上下反転ではバイト配列が異なる
always @(posedge pclk) begin
if (preset)
rgb565 <= 32'd0;
else begin
case (line_valid_1d_odd)
1'b0 : // 1番目
rgb565[31:13] <= {8'd0, cam_data_1d[7:3], 3'b000, cam_data_1d[2:0]}; // cam_data_1d = R7 R6 R5 R4 R3 G7 G6 G5
1'b1 : // 2番目
rgb565[12:0] <= {cam_data_1d[7:5], 2'b00, cam_data_1d[4:0], 3'b000}; // cam_data_1d = G4 G3 G2 B7 B6 B5 B4 B3
endcase
end
end
// rgb565 を 1 クロック遅延する
always @(posedge pclk) begin
if (preset) begin
rgb565_1d <= 32'd0;
end begin
rgb565_1d <= rgb565;
end
end
// line_valid の falling edge の検出
always @(posedge pclk) begin
if (preset) begin
last_pixel_4_line <= 1'b0;
end else if (line_valid_1d==1'b0 && line_valid_2d==1'b1) begin // line_valid_1d の falling edge
last_pixel_4_line <= 1'b1;
end else if (line_v_1d_odd_2d) begin
last_pixel_4_line <= 1'b0;
end
end
// frame_valid が 1 になってから初めてのピクセルを示す
always @(posedge pclk) begin
if (preset) begin
first_pixel <= 1'b0;
end else if (frame_valid_1d==1'b1 && frame_valid_2d==1'b0) begin // frame_valid_1d rising edge
first_pixel <= 1'b1;
end else if (line_v_1d_odd_2d) begin // first pixel
first_pixel <= 1'b0;
end
end
// pixel FIFO をインスタンスする
pixel_fifo pfifo (
.rst(areset), // input rst
.wr_clk(pclk), // input wr_clk
.rd_clk(aclk), // input rd_clk
.din({last_pixel_4_line, first_pixel, rgb565_1d}), // input [33 : 0] din
.wr_en(line_v_1d_odd_2d), // input wr_en
.rd_en(pfifo_rd_en), // input rd_en
.dout(pfifo_dout), // output [33 : 0] dout
.full(pfifo_full), // output full
.almost_full(pfifo_almost_full), // output almost_full
.overflow(pfifo_overflow), // output overflow
.empty(pfifo_empty), // output empty
.almost_empty(pfifo_almost_empty), // output almost_empty
.underflow(pfifo_underflow), // output underflow
.rd_data_count(pfifo_rd_data_count) // output [9 : 0] rd_data_count
);
endmodule
`default_nettype wire
// lap_filter_axis.h
// 2015/05/01
#define HORIZONTAL_PIXEL_WIDTH 800
#define VERTICAL_PIXEL_WIDTH 600
// #define HORIZONTAL_PIXEL_WIDTH 50
// #define VERTICAL_PIXEL_WIDTH 10
#define ALL_PIXEL_VALUE (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)
// lap_filter_axis.h
// 2015/05/01
#define HORIZONTAL_PIXEL_WIDTH 800
#define VERTICAL_PIXEL_WIDTH 600
// #define HORIZONTAL_PIXEL_WIDTH 50
// #define VERTICAL_PIXEL_WIDTH 10
#define ALL_PIXEL_VALUE (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)
となった。3613.050 ns - 283.050 ns = 3330.000 ns
となった。5020 ns / 3330 ns ≒ 1.51 倍
日 | 月 | 火 | 水 | 木 | 金 | 土 |
---|---|---|---|---|---|---|
- | - | - | - | - | 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 | - | - | - | - | - | - |