H2 Connect with Joining Automata

Synthesis of a P2P connection using a joining automaton.

This example shows the use of the connect primitive to join a pair of interfaces. In this example, the interfaces are not compatible, and a joining automata is needed.

The sending interface is a Centronix parallel port with its four-phase handhshake.

The receiving interface uses a two-phase handshake.

Source Code

The vanilla channel source code is given on the previous page. The rest is below.


//------------------------------------------------------------------
// Centronix components, in this version they are defined using imperative code:


// Physical level pin definitions
interface CENTRONIX_KERNEL()
{
   protocol centronix;

     forward:
        node out [7:0] : d8;
        node out : n_strobe;
        node in  : n_ack;
        node in  : busy;

  idle K.n_strobe ==0, K.n_ack == 0, K.busy == 0;
  initial K.n_strobe == 0;  
  initial K.busy == 0, K.n_ack == 0;
}


// Sending side
interface centronix_host(datasrc)
{
  node [7:0]: din;
  node forward CENTRONIX_KERNEL : K;

  {
    din =  ?datasrc;
    printf("Centronix host received %i\n", din);
    wait (!K.busy);
    play Sendop(din): 
    {
       K.d8 = din;
       pause();
       K.n_strobe = 1;
    } 
    wait (K.n_ack);
    K.n_strobe = 0;
    wait (!K.n_ack);
  }
}


// Receiving side
interface centronix_slave(datasink)
{
  node [7:0]: rxd;
  node reverse CENTRONIX_KERNEL : IF;  // This slave shown for completeness 
                                       // but not used in the experiment on
  {                                    // this page.
    IF.busy = 0;
    play Receiveop(rxd):
    {
        wait (IF.n_strobe);
	rxd = IF.d8;
    }
    printf("Centronix sink received %i\n", rxd);
    datasink ! rxd;
    IF.n_ack = 1;
    wait (!IF.n_strobe);
    IF.n_ack = 0;
  }
}

//---------------------------------------------------------------
// Two-phase interface, imperative specification in H2.
interface twophase_master(datasrc) 	//
{ node in [7:0]: dd8;			//  This master shown for completeness
  node out      : inflip;		//  but not used in the experiment on
  node in       : outflip;		//  this page.

  // locals
  node        : last;			//
  node   [7:0]: txd;			//
  {
     txd = ?datasrc;			//
     last = outflip;
     play Sendop(dd8):
	{
	 dd8 = txd;
	 pause();
         inflip = !last;
	}
    printf("Twophase master sent %i\n", txd);
    wait (last == outflip);
  }
  idle outflip == inflip, inflip == last;
  initial inflip == 0;
}

interface twophase_slave(datasink) 	//
{
  node in [7:0]: dd8;			//
  node in      : inflip;		//
  node out     : outflip;		//

  // locals
  node        : last;			//
  node   [7:0]: rxd;			//
  {
     last = inflip;
     play Receiveop(dd8):
	{
	wait (last != inflip);
	rxd = dd8;
	}
    printf("Twophase slave received %i\n", rxd);
    datasink ! rxd;			//
    outflip = inflip; // older: !outflip;
  }
  idle outflip == inflip, inflip == last; // FOR NOW
  initial outflip == 0, last == 0;
}

//---------------------------------------------------------------
// Test wrapper components now follow


//
// Connect a centronix source to a two phaser sink using a joining automata.
//
section JOINER1()
{
  channel [7:0]: inputstream, outputstream; 
  protocol vanilla_source : Source (inputstream);
  protocol centronix_host : Centronix_host (inputstream);
  protocol twophase_slave : Twophase_slave (outputstream);

  // Datapath data holding register.
  node [7:0] : roger;

  // The connect statement
  connect sink_to_src: left: Centronix_host, right: Twophase_slave mitre 
               { left: Sendop(roger); 
		right: Receiveop(roger);
               }
               // Lifebelt to avoid spurious ack wiggles.
               { wait (!n_strobe && !n_ack);     wait (n_strobe && !n_ack);
                 wait (n_strobe && n_ack);       wait (!n_strobe && n_ack);
               };
  protocol vanilla_sink : Sink (outputstream);
}
//
// eof

Simulation using builtin H2 simulator

The H2 tool has a builtin simulator which is run using the 'sim' command line flag, with events plotted to a plot file if requested.

./h2comp tests/directconnect.h2 -root JOINER1 -sim 280 -plot joiner.plt -title "Demonstration_of_FSM_joining_connect"  -vnl joiner.vnl -traces "Cent*,Two*,rog*,Sour*,Sink*"
Sending data 111
Centronix host transferring 111
Sending data 122
Twophase slave received X
Received X
Centronix host transferring 122
Sending data 133
Twophase slave received 111
Received 111
Centronix host transferring 133
Sending data 144
Twophase slave received 122
Received 122
Centronix host transferring 144
Sending data 155
Twophase slave received 133
Received 133
Centronix host transferring 155
Sending data 166
Twophase slave received 144
Received 144
Centronix host transferring 166
Sending data 177
Twophase slave received 155
Received 155
Centronix host transferring 177
Sending data 188
Twophase slave received 166
Received 166
Centronix host transferring 188
Sending data 199
Twophase slave received 177
Received 177
Centronix host transferring 199
Sending data 210
Twophase slave received 188
Simulation cycle limit reached at 280
h2comp done

Output Design

This plot demonstrates the correct operation of the connection.

Verilog RTL output and Microcode Output listings

Verilog RTL output and Microcode Output listings.

module connection_rebuild20222(clk, reset, Centronix_host_K_d8,
   Centronix_host_K_n_strobe, Centronix_host_K_n_ack,
   Centronix_host_K_busy, Twophase_slave_dd8, Twophase_slave_inflip,
   Twophase_slave_outflip);
   
   input clk;
   input reset;
   input [7:0] Centronix_host_K_d8;
   input Centronix_host_K_n_strobe;
   output Centronix_host_K_n_ack;
   output Centronix_host_K_busy;
   output [7:0] Twophase_slave_dd8;
   output Twophase_slave_inflip;
   input Twophase_slave_outflip;
   wire [2:0] pcnet122;
   wire [7:0] Centronix_host_din;
   wire Twophase_slave_last;
   wire [7:0] Twophase_slave_rxd;
   wire sand117;
   DFF it204(pcnet122[2], pcn122203, clk, 1, rst, 0);
   OR2 ipcn122203(pcn122203, san115129, pcn122202);
   OR2 ipcn122202(pcn122202, Cenack139, pcn122201);
   OR2 ipcn122201(pcn122201, Twodd8148, pcn122200);
   MUX2 ipcn122200(pcn122200, rogger161, 0, pcn122199);
   MUX2 ipcn122199(pcn122199, pcn122176, 0, pcn122198);
   MUX2 ipcn122198(pcn122198, pcn122177bar178, 0, pcn122197);
   OR2 ipcn122197(pcn122197, pcn122179bar180, pcnet122[2]);
   DFF it196(pcnet122[1], pcn122195, clk, 1, rst, 0);
   OR2 ipcn122195(pcn122195, san115129, pcn122194);
   MUX2 ipcn122194(pcn122194, Cenack139, 0, pcn122193);
   MUX2 ipcn122193(pcn122193, Twodd8148, 0, pcn122192);
   OR2 ipcn122192(pcn122192, rogger161, pcn122191);
   OR2 ipcn122191(pcn122191, pcn122176, pcn122190);
   MUX2 ipcn122190(pcn122190, pcn122177bar178, 0, pcn122189);
   OR2 ipcn122189(pcn122189, pcn122179bar180, pcnet122[1]);
   DFF it188(pcnet122[0], pcn122187, clk, 1, rst, 0);
   MUX2 ipcn122187(pcn122187, san115129, 0, pcn122186);
   OR2 ipcn122186(pcn122186, Cenack139, pcn122185);
   MUX2 ipcn122185(pcn122185, Twodd8148, 0, pcn122184);
   OR2 ipcn122184(pcn122184, rogger161, pcn122183);
   MUX2 ipcn122183(pcn122183, pcn122176, 0, pcn122182);
   OR2 ipcn122182(pcn122182, pcn122177bar178, pcn122181);
   MUX2 ipcn122181(pcn122181, pcn122179bar180, 0, pcnet122[0]);
   INV ipcn122179bar180(pcn122179bar180, pcn122179);
   OR2 ipcn122179(pcn122179, pcnet122[2], Cenack133);
   INV ipcn122177bar178(pcn122177bar178, pcn122177);
   OR2 ipcn122177(pcn122177, pcnet1222bar123, rogger158);
   AND2 ipcn122176(pcn122176, pcn122172bar173, pcn122174bar175);
   INV ipcn122174bar175(pcn122174bar175, pcn122174);
   XOR2 ipcn122174(pcn122174, Twophase_slave_outflip, sand117);
   INV ipcn122172bar173(pcn122172bar173, pcn122172);
   OR2 ipcn122172(pcn122172, pcnet122[2], san115125);
   DFF it171(roger[7], Centronix_host_K_d8[7], clk, rogger163, rst, 0);
   DFF it170(roger[6], Centronix_host_K_d8[6], clk, rogger163, rst, 0);
   DFF it169(roger[5], Centronix_host_K_d8[5], clk, rogger163, rst, 0);
   DFF it168(roger[4], Centronix_host_K_d8[4], clk, rogger163, rst, 0);
   DFF it167(roger[3], Centronix_host_K_d8[3], clk, rogger163, rst, 0);
   DFF it166(roger[2], Centronix_host_K_d8[2], clk, rogger163, rst, 0);
   DFF it165(roger[1], Centronix_host_K_d8[1], clk, rogger163, rst, 0);
   DFF it164(roger[0], Centronix_host_K_d8[0], clk, rogger163, rst, 0);
   OR2 irogger163(rogger163, san115129, rogger162);
   OR2 irogger162(rogger162, Cenack139, rogger161);
   AND2 irogger161(rogger161, rogger159bar160, Centronix_host_K_n_strobebar128);
   INV irogger159bar160(rogger159bar160, rogger159);
   OR2 irogger159(rogger159, pcnet122[2], rogger158);
   OR2 irogger158(rogger158, pcnet1221bar143, pcnet122[0]);
   DFF it157(Twophase_slave_inflip, sand117bar136, clk, Twodd8148, rst, 0);
   DFF it156(Twophase_slave_dd8[7], roger[7], clk, Twodd8148, rst, 0);
   DFF it155(Twophase_slave_dd8[6], roger[6], clk, Twodd8148, rst, 0);
   DFF it154(Twophase_slave_dd8[5], roger[5], clk, Twodd8148, rst, 0);
   DFF it153(Twophase_slave_dd8[4], roger[4], clk, Twodd8148, rst, 0);
   DFF it152(Twophase_slave_dd8[3], roger[3], clk, Twodd8148, rst, 0);
   DFF it151(Twophase_slave_dd8[2], roger[2], clk, Twodd8148, rst, 0);
   DFF it150(Twophase_slave_dd8[1], roger[1], clk, Twodd8148, rst, 0);
   DFF it149(Twophase_slave_dd8[0], roger[0], clk, Twodd8148, rst, 0);
   AND2 iTwodd8148(Twodd8148, Twodd8145bar146, Centronix_host_K_n_strobebar128bar147);
   INV iCentronix_host_K_n_strobebar128bar147(Centronix_host_K_n_strobebar128bar147, Centronix_host_K_n_strobebar128);
   INV iTwodd8145bar146(Twodd8145bar146, Twodd8145);
   OR2 iTwodd8145(Twodd8145, pcnet122[2], Twodd8144);
   OR2 iTwodd8144(Twodd8144, pcnet1221bar143, pcnet122bar124);
   INV ipcnet1221bar143(pcnet1221bar143, pcnet122[1]);
   DFF it142(Centronix_host_K_n_ack, Cenack141, clk, 1, rst, 0);
   MUX2 iCenack141(Cenack141, san115129, 0, Cenack140);
   OR2 iCenack140(Cenack140, Cenack139, Centronix_host_K_n_ack);
   AND2 iCenack139(Cenack139, Cenack134bar135, Cenack137bar138);
   INV iCenack137bar138(Cenack137bar138, Cenack137);
   XOR2 iCenack137(Cenack137, Twophase_slave_outflip, sand117bar136);
   INV isand117bar136(sand117bar136, sand117);
   INV iCenack134bar135(Cenack134bar135, Cenack134);
   OR2 iCenack134(Cenack134, pcnet1222bar123, Cenack133);
   OR2 iCenack133(Cenack133, pcnet122[1], pcnet122[0]);
   DFF it132(sand117, Twophase_slave_last, clk, san115129, rst, 0);
   AND2 isan115129(san115129, san115126bar127, Centronix_host_K_n_strobebar128);
   INV iCentronix_host_K_n_strobebar128(Centronix_host_K_n_strobebar128, Centronix_host_K_n_strobe);
   INV isan115126bar127(san115126bar127, san115126);
   OR2 isan115126(san115126, pcnet1222bar123, san115125);
   OR2 isan115125(san115125, pcnet122[1], pcnet122bar124);
   INV ipcnet122bar124(pcnet122bar124, pcnet122[0]);
   INV ipcnet1222bar123(pcnet1222bar123, pcnet122[2]);
endmodule

Partially Failed Output

This second plot shows an earlier and poorer quality design in operation. Because the annotation of the Receiveop does not prohibit additional changes in inflip, this earlier design was free to make them, wasting time.

TODO explain heuristic enhancement.


UP.