// $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