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.
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
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
This plot demonstrates the correct operation of the connection.
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
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.