Altera_Forum
Honored Contributor
14 years agoFrom Custom Instruction to Custom Peripheral
I'm trying to simulate how a camera works by generating lines of data and then apply some kind of spatial 3x3 convolution filter to the data. I have done one method by using Custom Instruction where I assume a 2-D image array is already available in NIOS and I then I used two for-loops to send 8 pixels x 8 bits each time to be processed in a combinatorial hardware module. The module was basically this code(with the inputs combined to be 2x32 inputs):
http://edge.kitiyo.com/2009/codes/sobel-core-verilog-module.html Now instead of doing two for-loops with a Hardware Instruction for each pixel, I want to do be able to send an entire row to emulate a camera, and then wait for 3 entire rows before doing the processing in hardware. I'm trying to do something like the Figure 2 in this paper. http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.108.8743&rep=rep1&type=pdf So I think my NIOS C code will look something like this.# define NUM_ROWS 4# define NUM_COLS 8
alt_u8 array_image = { /* fill in values */};
alt_u8* pointer8bit = 0;
alt_u32* pointer32bit = 0;
int num_32bit_values = NUM_COLS / 4; // Num 32bit values in one row.
for(row=0; row<(NUM_ROWS); row++)
{
pointer8bit = &(array_image);
pointer32bit = (alt_u32*) pointer8bit; // Convert pointer to interpret memory in chunks of 32 bits
for(n=0; n<(num_32bit_values); n++)
{
HARDWARE_CUSTOM_INSTRUCTION(pointer32bit); // Moves through array in 32bit steps transferring the row
}
}
But unlike with the Custom Instruction I did before, I need the HARDWARE_CUSTOM_INSTRUCTION to give a return value only when the transfer of a row has finished. The hardware module should also 'store' two rows of data at any time while it waits for the third one come and then do the processing. For example, with my 4x8 array above, there has to be 6 32-bit data transfers (2x32-bit transfer per row) to occur before I can do the Sobel operation in hardware. My questions are: - How do I store the 6 words in hardware and call part of each to do calculation? - How do I modify the original sobel code to achieve this? I need to have like a for-loop in hardware to go across the three rows. - After the initial 3 rows have arrived and calculations are done, then I need to drop the 'oldest' and bring it a new row. Any advice on how to do that? I don't think I can use Custom Instructions now right? I have to use Custom Peripherals with Avalon MM for example? I have tried sketching some verilog code for this (see below) but I don't know how to do the buffers in hardware. I am not sure how to use the data_en signal either. I only added it because I was trying to make a Avalon MM component and it asked for a write_n. Can somebody please give some guidance on this?
module my_sobel_test_mm (
// Inputs
clk,
reset,
data_in, //writedata
data_en, //write_n
// Outputs
data_out //readdata
);
// Inputs
input clk;
input reset;
input data_in;
input data_en;
// Outputs
output data_out;
/*****************************************************************************
* Internal wires and registers Declarations *
*****************************************************************************/
wire data_in_buffer_1;
wire data_in_buffer_2;
wire data_in_buffer_3;
// Internal Registers
reg line_1;
reg line_2;
reg line_3;
//11 bits because max value of gx and gy is 255*4 and last bit for sign
reg signed gx,gy;
//Find the absolute value of gx and gy
reg signed abs_gx,abs_gy;
//Max value is 255*8. here no sign bit needed.
reg sum;
reg result;
// Integers
integer i;
/*****************************************************************************
* Sequential logic *
*****************************************************************************/
// Sobel Operator
//
//
// Gx Gy
//
//
// |G| = |Gx| + |Gy|
always @(posedge clk)
begin
if (reset == 1'b1)
begin
for (i = 2; i >= 0; i = i-1)
begin
line_1 <= 8'h000;
line_2 <= 8'h000;
line_3 <= 8'h000;
end
gx <= 11'h000;
gy <= 11'h000;
abs_gx <= 11'h000;
abs_gy <= 11'h000;
result <= 8'h000;
end
else if (data_en == 1'b1)
begin
////// Dont know how to do this section //////////////
line_1 <= data_in_buffer_1;line_1 <= data_in_buffer_1;line_1 <= data_in_buffer_1;
line_2 <= data_in_buffer_2;line_2 <= data_in_buffer_2;line_2 <= data_in_buffer_2;
line_3 <= data_in_buffer_3;line_3 <= data_in_buffer_3;line_3 <= data_in_buffer_3;
//////////////////////////////////////////////////////
//sobel mask for gradient in horizontal direction
gx <=((line_1-line_1)+((line_2-line_2)<<1)+(line_3-line_3));
//sobel mask for gradient in vertical direction
gy <=((line_3-line_1)+((line_3-line_3)<<1)+(line_3-line_1));
// Absolute value of gx
abs_gx <= (gx? ~gx+1 : gx);
// Absolute value of gy
abs_gy <= (gy? ~gy+1 : gy);
// Sum
assign sum = (abs_gx+abs_gy);
// Max value 255
result <= (|sum)?8'hff : sum;
end
end
/*****************************************************************************
* Combinational logic *
*****************************************************************************/
assign data_out = result;
endmodule