/*************************************************************************** * * img_hw.c - Image Convolution Hardware Processes * * Copyright (c) 2004 by Green Mountain Computing Systems, Inc. * All rights reserved. * ***************************************************************************/ #include <stdio.h> #include "co.h" #include "cosim_log.h" #include "img.h" extern void call_fpga(co_memory imgmem, co_signal start, co_signal end); void to_stream(co_signal go, co_memory imgmem, co_stream output_stream) { int16 i, j; uint32 offset, data, d0; uint32 row[IMG_WIDTH / 2]; IF_SIM(cosim_logwindow log;) IF_SIM(log = cosim_logwindow_create("to_stream");) co_signal_wait(go, &data); co_stream_open(output_stream, O_WRONLY, INT_TYPE(32)); offset = 0; for ( i = 0; i < IMG_HEIGHT; i++ ) { co_memory_readblock(imgmem, offset, row, IMG_WIDTH * sizeof(int16)); for ( j = 0; j < (IMG_WIDTH / 2); j++ ) { #pragma CO PIPELINE d0 = row[j]; data = ((d0 >> 8) & 0xf8) << 16; data |= ((d0 >> 3) & 0xf8) << 8; data |= (d0 << 2) & 0xfc; co_stream_write(output_stream, &data, sizeof(int32)); d0 = d0 >> 16; data = ((d0 >> 8) & 0xf8) << 16; data |= ((d0 >> 3) & 0xf8) << 8; data |= (d0 << 2) & 0xfc; co_stream_write(output_stream, &data, sizeof(int32)); } offset += IMG_WIDTH * sizeof(int16); } data = 0; co_stream_write(output_stream, &data, sizeof(int32)); co_stream_write(output_stream, &data, sizeof(int32)); co_stream_close(output_stream); } /* The following process generates a marching three-pixel column in 3 separate output streams from the single input stream. This process can be used to feed pixels to any marching cubes image processing algorithm using a 3x3 kernel. It can easily be extended for other kernel sizes. For example, given a 5x5 image with the input stream: 0 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 this process will generate: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 This process generates 3-pixel columns every 2 cycles. */ void prep_run(co_stream input_stream, co_stream r0, co_stream r1, co_stream r2) { int32 i, j; int32 B[IMG_WIDTH], C[IMG_WIDTH]; int32 A01, A02, p02, p12, p22; IF_SIM(cosim_logwindow log;) IF_SIM(log = cosim_logwindow_create("prep_run");) co_stream_open(input_stream, O_RDONLY, INT_TYPE(32)); co_stream_open(r0, O_WRONLY, INT_TYPE(32)); co_stream_open(r1, O_WRONLY, INT_TYPE(32)); co_stream_open(r2, O_WRONLY, INT_TYPE(32)); co_stream_read(input_stream, &A01, sizeof(int32)); co_stream_read(input_stream, &A02, sizeof(int32)); for ( j = 0; j < IMG_WIDTH; j++ ) co_stream_read(input_stream, &B[j], sizeof(int32)); for ( j = 0; j < IMG_WIDTH; j++ ) co_stream_read(input_stream, &C[j], sizeof(int32)); co_stream_write(r0, &A01, sizeof(int32)); co_stream_write(r1, &B[IMG_WIDTH - 2], sizeof(int32)); co_stream_write(r2, &C[IMG_WIDTH - 2], sizeof(int32)); co_stream_write(r0, &A02, sizeof(int32)); co_stream_write(r1, &B[IMG_WIDTH - 1], sizeof(int32)); co_stream_write(r2, &C[IMG_WIDTH - 1], sizeof(int32)); for ( i = 2; i < IMG_HEIGHT; i++ ) { j = 0; do { p02 = B[j]; p12 = C[j]; co_stream_read(input_stream, &p22, sizeof(int32)); co_stream_write(r0, &p02, sizeof(int32)); co_stream_write(r1, &p12, sizeof(int32)); co_stream_write(r2, &p22, sizeof(int32)); B[j] = p12; C[j] = p22; j++; } while ( j < IMG_WIDTH ); } co_stream_close(input_stream); co_stream_close(r0); co_stream_close(r1); co_stream_close(r2); } #define RED(rgb) ((uint8)((rgb) >> 16)) #define GREEN(rgb) ((uint8)((rgb) >> 8)) #define BLUE(rgb) ((uint8)(rgb)) /* This process inputs a marching column of pixels from the prep_run process and applies a 3x3 convolution to the image to produce an output image on the output stream. A pipeline is utilized to generate one output pixel every two cycles. This particular convolution performs edge detection on the image. */ void filter_run(co_stream r0, co_stream r1, co_stream r2, co_stream output_stream) { uint32 data,res; uint32 p00, p01, p02, p10, p11, p12, p20, p21, p22; uint16 d0; IF_SIM(cosim_logwindow log;) IF_SIM(log = cosim_logwindow_create("filter_run");) co_stream_open(r0, O_RDONLY, INT_TYPE(32)); co_stream_open(r1, O_RDONLY, INT_TYPE(32)); co_stream_open(r2, O_RDONLY, INT_TYPE(32)); co_stream_open(output_stream, O_WRONLY, INT_TYPE(32)); p00 = 0; p01 = 0; p02 = 0; p10 = 0; p11 = 0; p12 = 0; p20 = 0; p21 = 0; p22 = 0; while ( co_stream_read(r0, &data, sizeof(int32)) == co_err_none ) { #pragma CO PIPELINE #pragma CO set stageDelay 256 p00 = p01; p01 = p02; p10 = p11; p11 = p12; p20 = p21; p21 = p22; p02 = data; co_stream_read(r1, &p12, sizeof(int32)); co_stream_read(r2, &p22, sizeof(int32)); d0 = RED(p11) << 3; d0 = d0 - RED(p00); d0 = d0 - RED(p01); d0 = d0 - RED(p02); d0 = d0 - RED(p10); d0 = d0 - RED(p12); d0 = d0 - RED(p20); d0 = d0 - RED(p21); d0 = d0 - RED(p22); d0 &= (d0 >> 15) - 1; res = d0 & 0xff; d0 = GREEN(p11) << 3; d0 = d0 - GREEN(p00); d0 = d0 - GREEN(p01); d0 = d0 - GREEN(p02); d0 = d0 - GREEN(p10); d0 = d0 - GREEN(p12); d0 = d0 - GREEN(p20); d0 = d0 - GREEN(p21); d0 = d0 - GREEN(p22); d0 &= (d0 >> 15) - 1; res = (res << 8) | (d0 & 0xff); d0 = BLUE(p11) << 3; d0 = d0 - BLUE(p00); d0 = d0 - BLUE(p01); d0 = d0 - BLUE(p02); d0 = d0 - BLUE(p10); d0 = d0 - BLUE(p12); d0 = d0 - BLUE(p20); d0 = d0 - BLUE(p21); d0 = d0 - BLUE(p22); d0 &= (d0 >> 15) - 1; res = (res << 8) | (d0 & 0xff); co_stream_write(output_stream, &res, sizeof(int32)); } co_stream_close(r0); co_stream_close(r1); co_stream_close(r2); co_stream_close(output_stream); } void from_stream(co_stream input_stream, co_memory imgmem, co_signal done) { uint8 err; int16 i; int32 offset, low, data, d0; int32 rowout[IMG_WIDTH / 2]; IF_SIM(cosim_logwindow log;) IF_SIM(log = cosim_logwindow_create("from_stream");) co_stream_open(input_stream, O_RDONLY, INT_TYPE(32)); offset = 0; do { for ( i = 0; i < (IMG_WIDTH / 2); i++ ) { #pragma CO PIPELINE err = co_stream_read(input_stream, &d0, sizeof(d0)); if ( err != co_err_none ) break; low = (d0 >> 19) & 0x1f; low = (low << 5) | ((d0 >> 11) & 0x1f); low = (low << 6) | ((d0 >> 2) & 0x3f); err = co_stream_read(input_stream, &d0, sizeof(d0)); if ( err != co_err_none) break; data = d0 >> 19; data = (data << 5) | ((d0 >> 11) & 0x1f); data = (data << 6) | ((d0 >> 2) & 0x3f); rowout[i] = (data << 16) | low; } if ( err != co_err_none) break; co_memory_writeblock(imgmem, offset, rowout, IMG_WIDTH * sizeof(int16)); offset += IMG_WIDTH * sizeof(int16); } while ( 1 ); co_stream_close(input_stream); co_signal_post(done, 0); } void config_img(void *arg) { int error; co_signal startsig, donesig; co_memory shrmem; co_stream istream, row0, row1, row2, ostream; co_process reader, writer; co_process cpu_proc, prep_proc, filter_proc; startsig = co_signal_create("start"); donesig = co_signal_create("done"); shrmem = co_memory_create("image", "heap0", IMG_WIDTH * IMG_HEIGHT * sizeof(uint16)); istream = co_stream_create("istream", INT_TYPE(32), IMG_HEIGHT/2); row0 = co_stream_create("row0", INT_TYPE(32), 4); row1= co_stream_create("row1", INT_TYPE(32), 4); row2 = co_stream_create("row2", INT_TYPE(32), 4); ostream = co_stream_create("ostream", INT_TYPE(32), IMG_HEIGHT/2); cpu_proc = co_process_create("cpu_proc", (co_function)call_fpga, 3, shrmem, startsig, donesig); reader = co_process_create("reader", (co_function)to_stream, 3, startsig, shrmem, istream); prep_proc = co_process_create("prep_proc", (co_function)prep_run, 4, istream, row0, row1, row2); filter_proc = co_process_create("filter", (co_function)filter_run, 4, row0, row1, row2, ostream); writer = co_process_create("writer", (co_function)from_stream, 3, ostream, shrmem, donesig); co_process_config(reader, co_loc, "PE0"); co_process_config(prep_proc, co_loc, "PE0"); co_process_config(filter_proc, co_loc, "PE0"); co_process_config(writer, co_loc, "PE0"); IF_SIM(error = cosim_logwindow_init();) } co_architecture co_initialize() { return(co_architecture_create("img_arch", "altera_nios2", config_img, NULL)); } |