2
\$\begingroup\$

Warning. I named signal w_tristate_decoder for other reason than it being tristate. w_tristate_decoder is just a name for ths signal., please do not be misled. Signals are NOT tristate in the question.

I am using MAX3000A CPLD, and need to convert signal values.

The circuit below significantly brakes the signal propagation, from 119 MHz to 87 MHz.

wire [2:0] w_tristate_decoder = (r_single_vector[23:20] == 4'b1101) ? 3'd7 :
                                            (r_single_vector[23:20] == 4'b0100) ? 3'd6 :
                                            (r_single_vector[23:20] == 4'b0111) ? 3'd5 :
                                            (r_single_vector[23:20] == 4'b0001) ? 3'd4 :
                                            (r_single_vector[23:20] == 4'b1111) ? 3'd3 :
                                            (r_single_vector[23:20] == 4'b1100) ? 3'd2 :
                                            (r_single_vector[23:20] == 4'b0011) ? 3'd1 :
                                                                                3'd0;       // 0000

I have tried this

wire [2:0] w_tristate_decoder7 = (r_single_vector[23:20] == 4'b1101) ? 3'd7 : 3'd0;
wire [2:0] w_tristate_decoder6 = (r_single_vector[23:20] == 4'b0100) ? 3'd6 : 3'd0;
wire [2:0] w_tristate_decoder5 = (r_single_vector[23:20] == 4'b0111) ? 3'd5 : 3'd0;
wire [2:0] w_tristate_decoder4 = (r_single_vector[23:20] == 4'b0001) ? 3'd4 : 3'd0;
wire [2:0] w_tristate_decoder3 = (r_single_vector[23:20] == 4'b1111) ? 3'd3 : 3'd0;
wire [2:0] w_tristate_decoder2 = (r_single_vector[23:20] == 4'b1100) ? 3'd2 : 3'd0;
wire [2:0] w_tristate_decoder1 = (r_single_vector[23:20] == 4'b0011) ? 3'd1 : 3'd0;

wire [2:0] w_tristate_decoder = w_tristate_decoder7[2:0] | w_tristate_decoder6[2:0] | w_tristate_decoder5[2:0] | w_tristate_decoder4[2:0] |
                                            w_tristate_decoder3[2:0] | w_tristate_decoder2[2:0] | w_tristate_decoder1[2:0];

and got the same result. Most probably former circuit is converted to latter at the synthesis stage.

Is there any way to change the former code to perform better without changing the tested signal values? This does not need to be priority encoder...

Edit: I get 119 MHz if do the following:

wire [2:0] w_tristate_decoder = (r_single_vector[23:20] == 4'b1101) ? 3'd7 :
//                                          (r_single_vector[23:20] == 4'b0100) ? 3'd6 :
//                                          (r_single_vector[23:20] == 4'b0111) ? 3'd5 :
//                                          (r_single_vector[23:20] == 4'b0001) ? 3'd4 :
//                                          (r_single_vector[23:20] == 4'b1111) ? 3'd3 :
//                                          (r_single_vector[23:20] == 4'b1100) ? 3'd2 :
//                                          (r_single_vector[23:20] == 4'b0011) ? 3'd1 :
                                                                                3'd0;       // 0000

Update: here's complete design.

module gr8net_vdp_cpld (
    // inputs
    input wire FCLK,        // data clock
    input wire B2,          // digital data bit 2
    input wire [1:0] B1,    // tristate data bit 1 from window comparators
    input wire [1:0] B0,    // tristate data bit 0 from window comparators
    // outputs
    (* altera_attribute = "-name FAST_OUTPUT_REGISTER ON" *)
    output wire w_wide_register_clock = 1'b0,               // clock to latch LVC16374
    (* altera_attribute = "-name FAST_OUTPUT_REGISTER ON" *)
    output wire w_small_register_clock = 1'b0,          // clock to latch 1G79
    (* altera_attribute = "-name FAST_OUTPUT_REGISTER ON" *)
    output reg [14:0] r_video_data = {15{1'b0}},        // video data bits, 3*5, red in [4:0], green in [9:5], and blue in [14:10]
    (* altera_attribute = "-name FAST_OUTPUT_REGISTER ON" *)
    output reg r_vs = 1'b1,
    (* altera_attribute = "-name FAST_OUTPUT_REGISTER ON" *)
    output reg r_hs = 1'b1      // negative polarity
);

// assemble into single vector
reg [24:0] r_single_vector = {25{1'b0}};    // 5*5 bits, we need 5 stages because when we detect sync_data, the vector
                                                        // is being shifted left on next clock when we extract data out of it
always@(negedge FCLK) begin
    r_single_vector[24:0] <= { r_single_vector[19:0], B2, B1[1:0], B0[1:0] };
end

// states: L=00, M=01, H=11
// detection of M/M state - most significant packet B1/B0 data are 01/01. They can not be 10/10, therefore using XOR
wire w_sync_data = (r_single_vector[18] ^ r_single_vector[17]) & (r_single_vector[16] ^ r_single_vector[15]);
reg r_sync_data = 1'b0;
reg initial_sync_detected = 1'b0;       // initially set to 0, will be set to 1 permanently when first sync data set is detected
                                                    // to start frame counting
always@(negedge FCLK) begin
    if(w_sync_data) initial_sync_detected <= 1'b1;  // set sync detected one permanently, enabling state machine
    r_sync_data <= w_sync_data;                         // preserve current sync data to be used on next state in next always circuit
end

wire [2:0] w_tristate_decoder = (r_single_vector[23:20] == 4'b1101) ? 3'd7 :
                                            (r_single_vector[23:20] == 4'b0100) ? 3'd6 :
                                            (r_single_vector[23:20] == 4'b0111) ? 3'd5 :
                                            (r_single_vector[23:20] == 4'b0001) ? 3'd4 :
                                            (r_single_vector[23:20] == 4'b1111) ? 3'd3 :
                                            (r_single_vector[23:20] == 4'b1100) ? 3'd2 :
                                            (r_single_vector[23:20] == 4'b0011) ? 3'd1 :
                                                                                                3'd0;       // 0000

reg [1:0] r_packet_state_machine = {2{1'b0}};
reg [15:0] r_color_data = {16{1'b0}};       // color data for output, bit 16 is unused
reg r_sync_data_n_lat = 1'b1;
always@(negedge FCLK) begin
    if(initial_sync_detected) begin
        // start state machine only when initial sync was detected, state 0 will be entered on the next clock
        // edge after sync data is detected, therefore on entry r_single_vector[24:5] will contain full sync vector,
        // r_sync_data contains actual sync state flag 
        case(r_packet_state_machine[1:0])
            2'd0:   begin
                        // we have full vector in r_single_vector[24:5] and r_sync_data contains sync data flag
                        r_sync_data_n_lat <= ~r_sync_data;      // preserve sync data flag to be used in next states
                        if(r_sync_data) begin
                            // current frame is sync - latch 
                            r_vs <= r_single_vector[19];
                            r_hs <= r_single_vector[15];
                        end else begin
                            // not sync - decode 5 bis into 4 bits into color output register if current frame is not sync
                            r_color_data[15:0] <= { r_color_data[11:0], r_single_vector[24], w_tristate_decoder[2:0] };
                        end
                        // put actual color data into the output, will be clocked into external registers on state 2
                        r_video_data[14:0] <= r_color_data[14:0];       // MSB is discarded
                    end
            2'd1,
            2'd2,
            2'd3:   begin
                        if(r_sync_data_n_lat) begin
                            // not sync - decode 5 bis into 4 bits into color output register if current frame is not sync
                            r_color_data[15:0] <= { r_color_data[11:0], r_single_vector[24], w_tristate_decoder[2:0] };
                        end
                        // if sync data - do nothing on color data
                    end
        endcase
        // increment state - only if initial sync was detected
        r_packet_state_machine[1:0] <= r_packet_state_machine[1:0] + 1'b1;
    end
end

// output register clocking - data will be output at state 0, and clocked into external ouput register
// on state 2 (posedge operation)
assign w_wide_register_clock = r_packet_state_machine[1];
assign w_small_register_clock = r_packet_state_machine[1];

endmodule

Update: after closely considering the circuits using RTL viewer and doing some experiments I redesigned the whole circuit using conveyor technique, and it lowered macrocells used from 64 to 54, and Fmax to be 129 MHz.

\$\endgroup\$
5
  • \$\begingroup\$ to be clear, you get 119MHz if you write for example wire [2:0] w_tristate_decoder = r_single_vector[23:21] | r_single_vector[22:20]; just as a test? \$\endgroup\$ Commented Mar 2, 2023 at 20:27
  • 1
    \$\begingroup\$ @user253751 updated the question \$\endgroup\$
    – Anonymous
    Commented Mar 2, 2023 at 20:48
  • \$\begingroup\$ Weird. Each tristate wire is easily the output of a single macrocell, single product term ("119 MHz") or three. From this signal name I figure none of the patterns not mentioned results in any don't care output - otherwise indicate in the question. \$\endgroup\$
    – greybeard
    Commented Mar 3, 2023 at 5:57
  • \$\begingroup\$ @greybeard Are you confused by the signal name? I can name it w_sevenstate_decoder, would you say the code and resulting circuit is not synthesizable then? The fact seems is this priority decoder is sequential. I ask if it is possible to streamline it somehow to decrease data propagation delay (and therefore increasing Fmax of the design). \$\endgroup\$
    – Anonymous
    Commented Mar 3, 2023 at 7:36
  • 1
    \$\begingroup\$ [is greybeard] confused by the signal name [w_tristate_decoder]? I hope not: I expect it to be a tri-state driver enable signal (or three enables). I don't see priority decoder. I remember priority encoders. \$\endgroup\$
    – greybeard
    Commented Mar 3, 2023 at 7:42

1 Answer 1

2
\$\begingroup\$

The speed difference is probably because the design gets larger when you use your complete example.

In the 119MHz case your code will reduce to a single macrocell with 4-inputs and one output feeding all three bits - because all three bits take the same value, either all a 1, or all a 0. So the circuit is more compact.

In the 87MHz example, you will now have three 4-in macrocells, one for each output bit, because each bit relates to the inputs differently. This means the design is going to larger, leading to more delays.

The difference works out to be around 3ns. Based on the MAX 3000A Programmable Logic Device Family Data Sheet page 29, that doesn't seem unreasonable for a small change in logic given that lots of the delays given for things like interconnects and logic array elements are on the order of 1ns to 4ns.

To get a more complete answer, you would have to give a better overview of how your code snippet fits into the larger design. Alternatively use the timing analysis and technology map viewer tools in Quartus to see how the design changes are interpretted. My gut feeling is there's little you can do to improve things short of getting a faster CPLD.

\$\endgroup\$
1
  • \$\begingroup\$ thanks. added full design \$\endgroup\$
    – Anonymous
    Commented Mar 3, 2023 at 10:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.