// $Id: vertsw.cs,v 1.7 2011/01/28 13:43:36 djg11 Exp $
// Kiwi Scientific Acceleration
// vertical version: msrc
// Example data: test against self
// M K F L V L L
// database: mkflvll = 10 8 4 9 17 9 9
// self score 6 5 9 6 4 6 6
// total score 6 11 20 26 30 36 42
// query: mfqafp = 10 4 13 0 4 12
//
// http://www.public.asu.edu/~cbaral/cse591-s03/classnotes/seq-align.pdf
// http://docencia.ac.upc.edu/master/AMPP/slides/ampp_sw_presentation.pdf
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using KiwiSystem;
// Vertical SW design.
namespace ParallelSW
{
// The idea is to have a number of KiwiTop designs that kiwic can proceess
// to try out different hardware structures. Each instantiates a Core, but
// with different parameters and so on. We can also have different methods
// inside the KiwiTop designs that we select to designate as the entry point.
// Root classes for kiwic need to be static.
static class KiwiTop_1
{
static bool alive = true;
public static void exit()
{
alive = false;
}
public static /* sealed const */ bool runserially = false;
public static object simlock = new object();
public static short[,] raw_pam250()
{
short [,] r = new short[21, 21] {
//A C D E F G H I K L M N P Q R S T V W Y Z
{ 2, -2, 0, 0, -4, 1, -1, -1, -1, -2, -1, 0, 1, 0, -2, 1, 1, 0, -6, -3, 0}, // A
{-2, 12, -5, -5, -4, -3, -3, -2, -5, -6, -5, -4, -3, -5, -4, 0, -2, -2, -8, 0, -3}, // C
{ 0, -5, 4, 3, -6, 1, 1, -2, 0, -4, -3, 2, -1, 2, -1, 0, 0, -2, -7, -4, -1}, // D
{ 0, -5, 3, 4, -5, 0, 1, -2, 0, -3, -2, 1, -1, 2, -1, 0, 0, -2, -7, -4, -1}, // E
{-4, -4, -6, -5, 9, -5, -2, 1, -5, 2, 0, -4, -5, -5, -4, -3, -3, -1, 0, 7, -2}, // F
{ 1, -3, 1, 0, -5, 5, -2, -3, -2, -4, -3, 0, -1, -1, -3, 1, 0, -1, -7, -5, -1}, // G
{-1, -3, 1, 1, -2, -2, 6, -2, 0, -2, -2, 2, 0, 3, 2, -1, -1, -2, -3, 0, -1}, // H
{-1, -2, -2, -2, 1, -3, -2, 5, -2, 2, 2, -2, -2, -2, -2, -1, 0, 4, -5, -1, -1}, // I
{-1, -5, 0, 0, -5, -2, 0, -2, 5, -3, 0, 1, -1, 1, 3, 0, 0, -2, -3, -4, -1}, // K
{-2, -6, -4, -3, 2, -4, -2, 2, -3, 6, 4, -3, -3, -2, -3, -3, -2, 2, -2, -1, -1}, // L
{-1, -5, -3, -2, 0, -3, -2, 2, 0, 4, 6, -2, -2, -1, 0, -2, -1, 2, -4, -2, -1}, // M
{ 0, -4, 2, 1, -4, 0, 2, -2, 1, -3, -2, 2, -1, 1, 0, 1, 0, -2, -4, -2, 0}, // N
{ 1, -3, -1, -1, -5, -1, 0, -2, -1, -3, -2, -1, 6, 0, 0, 1, 0, -1, -6, -5, -1}, // P
{ 0, -5, 2, 2, -5, -1, 3, -2, 1, -2, -1, 1, 0, 4, 1, -1, -1, -2, -5, -4, -1}, // Q
{-2, -4, -1, -1, -4, -3, 2, -2, 3, -3, 0, 0, 0, 1, 6, 0, -1, -2, 2, -4, -1}, // R
{ 1, 0, 0, 0, -3, 1, -1, -1, 0, -3, -2, 1, 1, -1, 0, 2, 1, -1, -2, -3, 0}, // S
{ 1, -2, 0, 0, -3, 0, -1, 0, 0, -2, -1, 0, 0, -1, -1, 1, 3, 0, -5, -3, 0}, // T
{ 0, -2, -2, -2, -1, -1, -2, 4, -2, 2, 2, -2, -1, -2, -2, -1, 0, 4, -6, -2, -1}, // V
{-6, -8, -7, -7, 0, -7, -3, -5, -3, -2, -4, -4, -6, -5, 2, -2, -5, -6, 17, 0, -4}, // W
{-3, 0, -4, -4, 7, -5, 0, -1, -4, -1, -2, -2, -5, -4, -4, -3, -3, -2, 0, 10, -2}, // Y
{ 0, -3, -1, -1, -2, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, 0, 0, -1, -4, -2, -1} // Z
};
return r;
}
[Kiwi.OutputBitPort("result_valid")] public static bool result_valid;
[Kiwi.OutputWordPort(31, 0)][Kiwi.OutputName("resultx")] public static int resultx;
[Kiwi.OutputWordPort(31, 0)][Kiwi.OutputName("progress_indicator")] public static int progress_indicator;
[Kiwi.OutputWordPort(31, 0)][Kiwi.OutputName("result_score")] public static int result_score;
[Kiwi.OutputWordPort(31, 0)][Kiwi.OutputName("seq_idx")] public static int seq_idx;
[Kiwi.InputWordPort(7, 0)][Kiwi.InputName("seq_data")] public static byte seq_data;
// Database and Query: load control signals
[Kiwi.InputBitPort("q_load")] public static bool q_load;
[Kiwi.InputBitPort("db_load")] public static bool db_load;
// Two-phase toggling handshake on each word sent.
[Kiwi.InputBitPort("req")] public static bool req;
[Kiwi.OutputBitPort("ack")] public static bool ack;
static void setup_KiwiTop_1() // static class constructor
{
pam250 = raw_pam250();
int swathe = (P.HardwiredQueryLimit + P.VCellCount - 1) / P.VCellCount;
CellArray = new vcell [P.VCellCount];
for (int cellidx=0; cellidx
= 'C' && ind <= 'I') ? 1 + ind - 'C':
(ind >= 'K' && ind <= 'N') ? 8 + ind - 'K':
(ind >= 'P' && ind <= 'T') ? 12 + ind -'P':
(ind >= 'V' && ind <= 'W') ? 17 + ind -'V':
(ind >= 'Y' && ind <= 'Z') ? 19 + ind -'Y':
-1;
return (byte) r;
}
// ---------------------------------------------------
public static class globals
{
static public byte [] passed_db = new byte [P.VCellCount];
static public short [] passed_score = new short [P.VCellCount];
static public int db_length, query_length;
}
public class vcell
{
int height, cellno;
public short cell_max;
public short [] prev, currentScore;
public byte [] seqd;
// [Kiwi.RomArray("pam250")] public short [,] lpam250;
public short [,] seqa;
public vcell(int u, int h) // Constructor.
{
// Console.WriteLine("Constructing {0}", u);
height = h; cellno = u;
currentScore = new short[height];
prev = new short[height];
// Old way seq + pam250
seqd = new byte[height]; // SEQ is set up by global access in parent!
//lpam250 = testdata.raw_pam250();
// New way: hold only relevant part of the score array in each cell.
seqa = new short[height, 21];
// Console.WriteLine("Constructed {0} {1}", u, cellno);
}
short diagonal_value;
public short run_vertical_cell()
{
int qpos;
byte dbval = globals.passed_db[cellno];
Console.WriteLine("Running vertical slice no {0}, dbval={1}", cellno, dbval);
const int unwind_factor = 4;
short aboveval = globals.passed_score[cellno];
cell_max = 0;
// Note that the prev array can dissappear from H/W entirely if whole cell is computed in one clock tick.
for (qpos = 0; qpos < height; qpos++) prev[qpos] = currentScore[qpos];
for (qpos = 0; qpos < height; qpos++)
{
// Enable this for mid-cell clock pausing (makes a slow design).
//if ((qpos % unwind_factor)== 0) Kiwi.Pause();
Kiwi.Pause(); // <----------
Console.WriteLine("tick qpos={0} height={1}", qpos, height);
Kiwi.Pause(); // <----------
if (seqd[qpos]==dbval) Console.Write(" FULLHIT ");
Kiwi.Pause(); // <----------
Console.Write(" seqval={0} ", seqd[qpos]);
Console.Write(" dbval={0} ", dbval);
Kiwi.Pause(); // <----------
short score = (dbval < 0) ? (short)0: seqa[qpos, dbval];
Console.WriteLine("tick cell {0}.{1} score={2}", cellno, qpos, score);
int diag = (qpos == 0) ? diagonal_value : prev[qpos - 1];
Console.WriteLine("tick diag={0}", diag);
//Kiwi.Pause();
int left = prev[qpos];
//Console.WriteLine("tick left={0}", left);
int above = (qpos==0) ? aboveval : currentScore[qpos-1];
//Console.WriteLine("tick above={0}", above);
//Kiwi.Pause(); // <----------
int nv = Math.Max(0, Math.Max(left - 10, Math.Max(above - 10, diag + score)));
currentScore[qpos] = (short)nv;
//Kiwi.Pause(); // <----------
Console.WriteLine("tick cell {0}.{1} nv={2}", cellno, qpos, nv);
if (nv > (int)cell_max)
{
Console.WriteLine("new cell max {0}", nv);
cell_max = (short)nv;
}
}
Console.WriteLine(" ... ran cell, cellno={0}, max={1}.", cellno, cell_max);
diagonal_value = aboveval;
return cell_max;
}
[Kiwi.Elaborate()] public bool busy;
public void SWOperator()
{
while(alive)
{
lock(this) { while (!busy) { Monitor.Wait(this); Kiwi.Pause(); } }
run_vertical_cell();
lock(this) { busy = false; Monitor.PulseAll(this); }
}
}
}
// Design Dimensions and other Parameters
public class P_main
{
public const int VCellCount=4;
public const int HardwiredQueryLimit=16;
public const int HardwiredDbLimit = 1000;
}
public class P // debug
{ // debug - quick test values
// 2,4,10 compiled in 2m13 on koo jab 2011
public const int VCellCount=2;
public const int HardwiredQueryLimit=4;
public const int HardwiredDbLimit = 10;
}
static byte [] query_seq = new byte [500]; // The max usable query is HardwiredQueryLimit defined in P
static byte [] temp_database = new byte [P.HardwiredDbLimit];
static vcell [] CellArray;
static void move1(int u, byte [] db_seq, int db_pos)
{
int swathe = (P.HardwiredQueryLimit + P.VCellCount - 1) / P.VCellCount;
globals.passed_db[u] = (u == 0) ? db_seq[db_pos]: globals.passed_db[u-1];
globals.passed_score[u] = (db_pos==0 || u == 0) ? (short)0: CellArray[u-1].currentScore[swathe-1];
// Console.WriteLine("Updated A flow score {0} to {1}", u, globals.passed_score[u]);
}
static void djgscore_parallel_dbitem(byte [] db_seq, int db_pos)
{
int swathe = (P.HardwiredQueryLimit + P.VCellCount - 1) / P.VCellCount;
for (int u = P.VCellCount-1; u>=0; u--)
{
move1(u, db_seq, db_pos);
}
Kiwi.Pause(); // <----------
progress_indicator = 100 + db_pos;
Console.WriteLine("Procesing db item {0} of {1}", db_pos, globals.db_length);
if (runserially)
{
for (int u = 0; u db_max)
{
db_max = CellArray[u].cell_max;
db_max_pos_x = db_pos;
Console.WriteLine("DUT: Updating db_max to {0} at {1}", db_max, db_pos);
// Copy to h/w output terminals
resultx = db_pos;
result_score = db_max;
}
}
}
Kiwi.Pause();
Console.WriteLine("DUT: PP final db_max for this db {0} at {1}", db_max, db_max_pos_x);
Console.WriteLine("DUT: Finished database length {0} at time {1}", globals.db_length, Kiwi.tnow);
Kiwi.Pause();
Console.WriteLine("DUT: finished compute.");
progress_indicator = 32; // thats it for now!
}
[Kiwi.RomArray("pam250")] public static short [,] pam250;
public static void copy_sub_matrix(int h, int sidx, int cellidx, byte [] query_seq)
{
int idx = sidx>= globals.query_length ? 0: (int)query_seq[sidx];
for (int i=0; i< 21; i++)
{ //Kiwi.Pause();
CellArray[cellidx].seqa[h, i] = pam250[idx, i];
Console.Write("{0} {1} set to {2}, ", h, i, pam250[idx, i]);
Console.Write("{0} {1} rb-p {2}, ", h, i, CellArray[cellidx].seqa[h, i]);
//Kiwi.Pause();
Console.Write("{0} {1} rb-a {2}, ", h, i, CellArray[cellidx].seqa[h, i]);
//Console.WriteLine();
}
Console.WriteLine();
}
public static void cell_setup(byte [] query_seq, byte [] db_seq)
{
int swathe = (P.HardwiredQueryLimit + P.VCellCount - 1) / P.VCellCount;
//
for (int cellidx=0; cellidx= globals.query_length ? (short)0: FAILS UNWIND */ (query_seq[sidx]);
// Kiwi.Pause();
Console.WriteLine("Sent Q to cells. readback {0} {1}", sidx, CellArray[cellidx].seqd[h]);
// Kiwi.Pause();
// OR...
// Just send the relevant part of the pam matrix, according to part of the query string,to each cell
copy_sub_matrix(h, sidx, cellidx, query_seq);
//for (int ii=0; ii< 21; ii++)
//{ Kiwi.Pause();
// Console.Write("{0} {1} rb {2}, ", h, ii, CellArray[cellidx].seqa[h, ii]);
//}
//Console.WriteLine();
}
Console.WriteLine("Sequence fragment {0} sent to cellidx {1}", cellidx*swathe, cellidx);
}
Kiwi.Pause();
}
public class Top_2_FullFeb
{
void queryreceive_engine()
{
int q_len = 0;
bool ended = false;
Console.WriteLine("DUT: PP start load a query at {0}\n", Kiwi.tnow);
while(q_load)
{
seq_idx = q_len;
lock(simlock) { while (req==ack) { Kiwi.Pause(); Monitor.Wait(simlock); } }
byte holding1 = seq_data;
if (holding1 == 0x3d && !ended)
{ Console.WriteLine("DUT: PP ended q load");
ended = true;
}
if (q_len == P.HardwiredQueryLimit)
{ Console.WriteLine("DUT: PP hardwired query limit ended load at {0}", q_len);
ended = true;
}
Console.WriteLine("DUT: Query LOAD {0} '{1}'\n", seq_idx, (char)holding1);
Kiwi.Pause();
if (q_len < P.HardwiredQueryLimit) query_seq[q_len] = (ended) ? (byte)0 : encoder(holding1);
q_len++;
lock(simlock) { ack = req; Monitor.PulseAll(simlock); }
Kiwi.Pause();
}
globals.query_length = q_len;
Console.WriteLine("DUT: PP Query Sequence xfer ceased at idx {0}\n", q_len);
}
void dbreceive_engine()
{ int db_len = 0; bool ended = false;
while (db_load)
{ seq_idx = db_len;
lock(simlock) { while (req==ack) { Kiwi.Pause(); Monitor.Wait(simlock); } }
byte holding2 = seq_data;
if (holding2 == 0x3d && !ended)
{ Console.WriteLine("DUT: PP ended db load");
ended = true;
}
if (db_len == P.HardwiredDbLimit)
{ Console.WriteLine("DUT: PP hardwired db limit ended load at {0}", db_len);
ended = true;
}
Kiwi.Pause();
if (db_len < P.HardwiredDbLimit) temp_database[db_len] = (ended) ? (byte)0: encoder(holding2);
Console.WriteLine("DUT: DB LOAD {0} '{1}'\n", db_len, (char)holding2);
db_len++;
lock(simlock) { ack = req; Monitor.PulseAll(simlock); }
if (seq_data == 0x3d) break;
Kiwi.Pause();
}
globals.db_length = db_len;
Console.WriteLine("DUT: PP Database xfer ceased at idx {0}\n", db_len);
}
public void main() // Entry point for the kiwic-compiled h/w design.
{
Console.WriteLine("Full nascence {0}\n", Kiwi.tnow);
result_score = -1;
seq_idx = 0;
setup_KiwiTop_1();
while(alive) // The outermost process loop for the h/w controller.
{
seq_idx = 0;
Kiwi.Pause();
result_valid = false;
progress_indicator = 1; // Result y is a debug/phase output at the moment
while (false && !q_load && !db_load) { Kiwi.Pause(); continue; }
if (q_load)
{
resultx = 0;
progress_indicator = 2; // Result y is a debug/phase output at the moment
Kiwi.Pause();
queryreceive_engine();
continue;
}
else if (db_load)
{
progress_indicator = 4; // Result y is a debug/phase output
Kiwi.Pause();
dbreceive_engine();
Console.WriteLine("DUT: PP Commence computation");
Kiwi.Pause();
progress_indicator = 6; // Result y is a debug/phase output
Kiwi.Pause();
//Run automatically when get here... for now.
// Kiwi.NeverReached("This is reached 0 !");
cell_setup(query_seq, temp_database);
// Kiwi.NeverReached("This is reached 1 !");
Console.WriteLine("Commence computation: runserially={0} at time {1}", runserially, Kiwi.tnow);
djgscore_compute(temp_database);
// Wont return to me here: well takes 20 mins actually.
// Kiwi.NeverReached("This is reached 2!");
Console.WriteLine("Computation done.");
// Kiwi.NeverReached("Done me post parallel call.");
// Unreachable code: parallel does not yet return.
progress_indicator = 10; // Result y is a debug/phase output
Console.WriteLine("FullFeb result x={0}, y={1}\n", resultx, (char)progress_indicator);
result_valid = true;
}
else Kiwi.Pause();
}
}
}
// static class (kiwic I think needs a static -root but we cannot use the LOCK feature in a static class, so immediately spawn a dynamic one...).
public static void Top_1_FullFeb()
{
Top_2_FullFeb DUT = new Top_2_FullFeb();
DUT.main();
}
}
}
// eof