/*
 * Copyright (c) 2015-2016, Sumio Morioka
 * All rights reserved.
 *
 * This source code was originally written by Dr.Sumio Morioka for use in the 2015-2016 issues of 
 * "the Interface magazine", published by CQ publishing Co.Ltd in Japan (http://www.cqpub.co.jp).
 * The author has no responsibility on any results caused by using this code.
 *
 * - Author: Dr.Sumio Morioka (http://www002.upp.so-net.ne.jp/morioka, FB:Sumio Morioka)
 *
 *
 * IMPORTANT NOTICE:
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *   * Neither the name of the copyright holder nor the
 *     names of its contributors may be used to endorse or promote products
 *     derived from this software/hardware without specific prior written permission.
 *
 * THIS SOFTWARE/HARDWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE/HARDWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

//////////////////////////////////////////////////////////////////////////
// shared memory
//////////////////////////////////////////////////////////////////////////
#include <ap_cint.h>
#include <ap_utils.h>

////////////////////////////////////////////
// port
////////////////////////////////////////////

// ch0
volatile uint8	addr0	= 0;
volatile uint8	din0;
volatile uint8	dout0	= 0;
volatile uint1	r_req0;
volatile uint1	r_ack0	= 0;
volatile uint1	w_req0;
volatile uint1	w_ack0	= 0;

// ch1
volatile uint8	addr1	= 0;
volatile uint8	din1;
volatile uint8	dout1	= 0;
volatile uint1	r_req1;
volatile uint1	r_ack1	= 0;
volatile uint1	w_req1;
volatile uint1	w_ack1	= 0;

// ch2
volatile uint8	addr2	= 0;
volatile uint8	din2;
volatile uint8	dout2	= 0;
volatile uint1	r_req2;
volatile uint1	r_ack2	= 0;
volatile uint1	w_req2;
volatile uint1	w_ack2	= 0;

// ch3
volatile uint8	addr3	= 0;
volatile uint8	din3;
volatile uint8	dout3	= 0;
volatile uint1	r_req3;
volatile uint1	r_ack3	= 0;
volatile uint1	w_req3;
volatile uint1	w_ack3	= 0;

////////////////////////////////////////////
// main
////////////////////////////////////////////

void sharedmem()
{
#pragma HLS TOP

#pragma HLS INTERFACE ap_none port=addr0 register
#pragma HLS INTERFACE ap_none port=din0
#pragma HLS INTERFACE ap_none port=dout0 register
#pragma HLS INTERFACE ap_none port=r_req0
#pragma HLS INTERFACE ap_none port=r_ack0 register
#pragma HLS INTERFACE ap_none port=w_req0
#pragma HLS INTERFACE ap_none port=w_ack0 register

#pragma HLS INTERFACE ap_none port=addr1 register
#pragma HLS INTERFACE ap_none port=din1
#pragma HLS INTERFACE ap_none port=dout1 register
#pragma HLS INTERFACE ap_none port=r_req1
#pragma HLS INTERFACE ap_none port=r_ack1 register
#pragma HLS INTERFACE ap_none port=w_req1
#pragma HLS INTERFACE ap_none port=w_ack1 register

#pragma HLS INTERFACE ap_none port=addr2 register
#pragma HLS INTERFACE ap_none port=din2
#pragma HLS INTERFACE ap_none port=dout2 register
#pragma HLS INTERFACE ap_none port=r_req2
#pragma HLS INTERFACE ap_none port=r_ack2 register
#pragma HLS INTERFACE ap_none port=w_req2
#pragma HLS INTERFACE ap_none port=w_ack2 register

#pragma HLS INTERFACE ap_none port=addr3 register
#pragma HLS INTERFACE ap_none port=din3
#pragma HLS INTERFACE ap_none port=dout3 register
#pragma HLS INTERFACE ap_none port=r_req3
#pragma HLS INTERFACE ap_none port=r_ack3 register
#pragma HLS INTERFACE ap_none port=w_req3
#pragma HLS INTERFACE ap_none port=w_ack3 register

	uint8	ch	= 0;

	uint8	mem[256];		// body of memory
	uint9	addr;			// note; not 8bit

	ap_wait();
	r_ack0	= 0;
	w_ack0	= 0;
	r_ack1	= 0;
	w_ack1	= 0;
	r_ack2	= 0;
	w_ack2	= 0;
	r_ack3	= 0;
	w_ack3	= 0;
	ap_wait();

	for (addr = 0; addr < 256; addr++) {
		mem[addr]	= 0;
	}

	// main loop
	while (1) {
		switch (ch) {
		case 0:		// no channel
			if (r_req0 == 1 || w_req0 == 1)
				ch	= 1;
			else if (r_req1 == 1 || w_req1 == 1)
				ch	= 2;
			else if (r_req2 == 1 || w_req2 == 1)
				ch	= 3;
			else if (r_req3 == 1 || w_req3 == 1)
				ch	= 4;
			break;

		case 1:		// ch0
			if (r_req0 == 1) {
				ap_wait();
				dout0	= mem[addr0];
				ap_wait();
				while (r_req0 == 1) {
					r_ack0	= 1;
				}
				ap_wait();
				r_ack0	= 0;
				ap_wait();
			}
			else if (w_req0 == 1) {
				ap_wait();
				mem[addr0]	= din0;
				ap_wait();
				while (w_req0 == 1) {
					w_ack0	= 1;
				}
				ap_wait();
				w_ack0	= 0;
				ap_wait();
			}
			ch	= 0;
			break;

		case 2:		// ch1
			if (r_req1 == 1) {
				ap_wait();
				dout1	= mem[addr1];
				ap_wait();
				while (r_req1 == 1) {
					r_ack1	= 1;
				}
				ap_wait();
				r_ack1	= 0;
				ap_wait();
			}
			else if (w_req1 == 1) {
				ap_wait();
				mem[addr1]	= din1;
				ap_wait();
				while (w_req1 == 1) {
					w_ack1	= 1;
				}
				ap_wait();
				w_ack1	= 0;
				ap_wait();
			}
			ch	= 0;
			break;

		case 3:		// ch2
			if (r_req2 == 1) {
				ap_wait();
				dout2	= mem[addr2];
				ap_wait();
				while (r_req2 == 1) {
					r_ack2	= 1;
				}
				ap_wait();
				r_ack2	= 0;
				ap_wait();
			}
			else if (w_req2 == 1) {
				ap_wait();
				mem[addr2]	= din2;
				ap_wait();
				while (w_req2 == 1) {
					w_ack2	= 1;
				}
				ap_wait();
				w_ack2	= 0;
				ap_wait();
			}
			ch	= 0;
			break;

		case 4:		// ch3
			if (r_req3 == 1) {
				ap_wait();
				dout3	= mem[addr3];
				ap_wait();
				while (r_req3 == 1) {
					r_ack3	= 1;
				}
				ap_wait();
				r_ack3	= 0;
				ap_wait();
			}
			else if (w_req3 == 1) {
				ap_wait();
				mem[addr3]	= din3;
				ap_wait();
				while (w_req3 == 1) {
					w_ack3	= 1;
				}
				ap_wait();
				w_ack3	= 0;
				ap_wait();
			}
			ch	= 0;
			break;

		default:
			ap_wait();
			r_ack0	= 0;
			w_ack0	= 0;
			r_ack1	= 0;
			w_ack1	= 0;
			r_ack2	= 0;
			w_ack2	= 0;
			r_ack3	= 0;
			w_ack3	= 0;
			ap_wait();

			ch	= 0;
			break;
		}
	}
}

// end of file
