| module scalable_proc # | 
 | ( | 
 | parameter NUM_PROCESSING_UNITS  = 2,    // Number of processing units | 
 | parameter UART_PRESCALER        = 868   // UART prescaler | 
 | ) | 
 | ( | 
 | // Closk & reset | 
 | input  wire CLK, | 
 | input  wire RST, | 
 |  | 
 | // UART | 
 | input  wire UART_RX, | 
 | output wire UART_TX | 
 | ); | 
 |  | 
 | // ============================================================================ | 
 | // ROM | 
 | wire         rom_i_stb; | 
 | reg  [31:0]  rom_i_adr; // Fixed to 32-bit. The ROM size must be a power of 2 less than 32 | 
 | wire         rom_o_stb; | 
 | wire [31:0]  rom_o_dat; | 
 |  | 
 | rom rom | 
 | ( | 
 | .CLK    (CLK), | 
 | .RST    (RST), | 
 |  | 
 | .I_STB  (rom_i_stb), | 
 | .I_ADR  (rom_i_adr), | 
 | .O_STB  (rom_o_stb), | 
 | .O_DAT  (rom_o_dat) | 
 | ); | 
 |  | 
 | // UART transmitt interval | 
 | localparam UART_TX_INTERVAL = UART_PRESCALER * 11; // Wait for 10-bits + 1 extra | 
 |  | 
 | // ============================================================================ | 
 | // Input shift register | 
 | localparam SREG_BITS = 32 * NUM_PROCESSING_UNITS; | 
 |  | 
 | reg  [SREG_BITS-1:0] inp_sreg; | 
 |  | 
 | wire        inp_sreg_i_stb = rom_o_stb; | 
 | wire [31:0] inp_sreg_i_dat = rom_o_dat; | 
 | reg         inp_sreg_o_stb; | 
 |  | 
 | always @(posedge CLK) | 
 |     if (inp_sreg_i_stb) inp_sreg <= {inp_sreg[SREG_BITS-32-1:0], inp_sreg_i_dat}; | 
 |     else                inp_sreg <=  inp_sreg; | 
 |  | 
 | always @(posedge CLK or posedge RST) | 
 |     if (RST)    inp_sreg_o_stb <= 1'd0; | 
 |     else        inp_sreg_o_stb <= inp_sreg_i_stb; | 
 |  | 
 | // ============================================================================ | 
 | // Processing units | 
 | reg                             proc_i_stb; | 
 | wire [NUM_PROCESSING_UNITS-1:0] proc_o_stb; | 
 | wire [SREG_BITS-1:0]            proc_o_dat; | 
 |  | 
 | genvar i; | 
 | generate for(i=0; i<NUM_PROCESSING_UNITS; i=i+1) begin | 
 |     processing_unit unit | 
 |     ( | 
 |     .CLK    (CLK), | 
 |     .RST    (RST), | 
 |     .I_STB  (proc_i_stb), | 
 |     .I_DAT  (inp_sreg[(i+1)*32-1 : i*32]), | 
 |     .O_STB  (proc_o_stb[i]), | 
 |     .O_DAT  (proc_o_dat[(i+1)*32-1 : i*32]) | 
 |     ); | 
 | end endgenerate | 
 |  | 
 | // ============================================================================ | 
 | // Output shift register | 
 | reg  [SREG_BITS-1:0] out_sreg; | 
 |  | 
 | wire                 out_sreg_i_ld  = proc_o_stb[0]; | 
 | wire [SREG_BITS-1:0] out_sreg_i_dat = proc_o_dat; | 
 | wire                 out_sreg_i_sh; | 
 | reg                  out_sreg_o_stb; | 
 | wire [3:0]           out_sreg_o_dat; | 
 |  | 
 | always @(posedge CLK) | 
 |     if      (out_sreg_i_ld) out_sreg <= out_sreg_i_dat; | 
 |     else if (out_sreg_i_sh) out_sreg <= out_sreg << 4; | 
 |     else                    out_sreg <= out_sreg; | 
 |  | 
 | assign out_sreg_o_dat = out_sreg[SREG_BITS-1:SREG_BITS-4]; | 
 |  | 
 | // DEBUG | 
 | always @(posedge CLK) | 
 |     if (proc_o_stb) $display("%X", {4'dx, proc_o_dat}); | 
 |  | 
 | // ============================================================================ | 
 | // Control FSM | 
 | localparam STATE_INIT       = 0; | 
 |  | 
 | localparam STATE_LOAD_START = 10; | 
 | localparam STATE_LOAD_SHIFT = 11; | 
 |  | 
 | localparam STATE_PROC_START = 20; | 
 | localparam STATE_PROC_WAIT  = 21; | 
 |  | 
 | localparam STATE_SEND_START = 30; | 
 | localparam STATE_SEND_WAIT  = 31; | 
 | localparam STATE_SEND_DELIM = 32; | 
 |  | 
 | integer     fsm; | 
 | reg [32:0]  fsm_cnt; | 
 |  | 
 | wire        fsm_pulse; | 
 | reg [32:0]  fsm_pulse_cnt; | 
 |  | 
 | // fsm | 
 | always @(posedge CLK or posedge RST) | 
 |     if (RST) fsm <= STATE_INIT; | 
 |     else case(fsm) | 
 |  | 
 |     STATE_INIT:         fsm <= STATE_LOAD_START; | 
 |  | 
 |     STATE_LOAD_START:   fsm <= STATE_LOAD_SHIFT; | 
 |     STATE_LOAD_SHIFT:   fsm <= (fsm_cnt[32])   ? STATE_PROC_START : fsm; | 
 |  | 
 |     STATE_PROC_START:   fsm <= STATE_PROC_WAIT; | 
 |     STATE_PROC_WAIT:    fsm <= (proc_o_stb[0]) ? STATE_SEND_START : fsm; | 
 |  | 
 |     STATE_SEND_START:   fsm <= STATE_SEND_WAIT; | 
 |     STATE_SEND_WAIT:    if (fsm_pulse) fsm <= (fsm_cnt[32]) ? STATE_SEND_DELIM : fsm; | 
 |     STATE_SEND_DELIM:   if (fsm_pulse) fsm <= STATE_INIT; | 
 |  | 
 |     endcase | 
 |  | 
 | // fsm_cnt | 
 | always @(posedge CLK) | 
 |     case (fsm) | 
 |  | 
 |     STATE_LOAD_START:   fsm_cnt <= NUM_PROCESSING_UNITS - 2; // 32-bits per shift | 
 |  | 
 |     STATE_SEND_START:   fsm_cnt <= NUM_PROCESSING_UNITS * (32 / 4) - 2; // 4-bits per shift | 
 |     STATE_SEND_WAIT:    if (fsm_pulse) fsm_cnt <= (fsm_cnt[32]) ? fsm_cnt : (fsm_cnt - 1); | 
 |  | 
 |     default:            fsm_cnt <= (fsm_cnt[32]) ? fsm_cnt : (fsm_cnt - 1); | 
 |  | 
 |     endcase | 
 |  | 
 | // fsm_pulse_cnt | 
 | always @(posedge CLK or posedge RST) | 
 |     if (RST) fsm_pulse_cnt <=                       UART_TX_INTERVAL - 2; | 
 |     else     fsm_pulse_cnt <= (fsm_pulse_cnt[31]) ? UART_TX_INTERVAL - 2 : fsm_pulse_cnt - 1; | 
 |  | 
 | assign fsm_pulse = fsm_pulse_cnt[31]; | 
 |  | 
 | // ============================================================================ | 
 | // Control signals | 
 | wire        uart_i_stb; | 
 | wire [4:0]  uart_i_dat; | 
 |  | 
 | assign rom_i_stb = (fsm == STATE_LOAD_SHIFT); | 
 |  | 
 | always @(posedge CLK or posedge RST) | 
 |     if (RST)          rom_i_adr <= 0; | 
 |     else case(fsm) | 
 |     STATE_LOAD_SHIFT: rom_i_adr <= rom_i_adr + 1; | 
 |     default:          rom_i_adr <= rom_i_adr; | 
 |     endcase | 
 |  | 
 | always @(posedge CLK or posedge RST) | 
 |     if (RST) proc_i_stb <= 0; | 
 |     else     proc_i_stb <= (fsm == STATE_PROC_START); | 
 |  | 
 | assign out_sreg_i_sh = (fsm == STATE_SEND_WAIT) && fsm_pulse; | 
 |  | 
 | assign uart_i_stb    = fsm_pulse && ((fsm == STATE_SEND_WAIT) ||  | 
 |                                      (fsm == STATE_SEND_DELIM)); | 
 |  | 
 | assign uart_i_dat    = (fsm == STATE_SEND_WAIT)  ? {1'd0, out_sreg_o_dat} : | 
 |                        (fsm == STATE_SEND_DELIM) ? {1'd1, 4'd0} :  | 
 |                                                    {1'd1, 4'd0}; | 
 |  | 
 | // ============================================================================ | 
 | // UART string generator | 
 | reg         uart_x_stb; | 
 | reg  [7:0]  uart_x_dat; | 
 |  | 
 | always @(posedge CLK) | 
 |     case (uart_i_dat) | 
 |  | 
 |     5'h00:   uart_x_dat <= "0"; | 
 |     5'h01:   uart_x_dat <= "1"; | 
 |     5'h02:   uart_x_dat <= "2"; | 
 |     5'h03:   uart_x_dat <= "3"; | 
 |     5'h04:   uart_x_dat <= "4"; | 
 |     5'h05:   uart_x_dat <= "5"; | 
 |     5'h06:   uart_x_dat <= "6"; | 
 |     5'h07:   uart_x_dat <= "7"; | 
 |     5'h08:   uart_x_dat <= "8"; | 
 |     5'h09:   uart_x_dat <= "9"; | 
 |     5'h0A:   uart_x_dat <= "A"; | 
 |     5'h0B:   uart_x_dat <= "B"; | 
 |     5'h0C:   uart_x_dat <= "C"; | 
 |     5'h0D:   uart_x_dat <= "D"; | 
 |     5'h0E:   uart_x_dat <= "E"; | 
 |     5'h0F:   uart_x_dat <= "F"; | 
 |  | 
 |     5'h10:   uart_x_dat <= "\n"; | 
 |  | 
 |     default: uart_x_dat <= " "; | 
 |  | 
 |     endcase | 
 |  | 
 | always @(posedge CLK or posedge RST) | 
 |     if (RST)    uart_x_stb <= 1'd0; | 
 |     else        uart_x_stb <= uart_i_stb; | 
 |  | 
 | // ============================================================================ | 
 | // UART | 
 |  | 
 | // Baudrate prescaler initializer | 
 | reg  [7:0]  reg_div_we_sr; | 
 | wire        reg_div_we; | 
 |  | 
 | always @(posedge CLK or posedge RST) | 
 |     if (RST)    reg_div_we_sr <= 8'h01; | 
 |     else        reg_div_we_sr <= {reg_div_we_sr[6:0], 1'd0}; | 
 |  | 
 | assign reg_div_we = reg_div_we_sr[7]; | 
 |  | 
 | // The UART | 
 | simpleuart uart | 
 | ( | 
 | .clk            (CLK), | 
 | .resetn         (!RST), | 
 |  | 
 | .ser_rx         (UART_RX), | 
 | .ser_tx         (UART_TX), | 
 |  | 
 | .reg_div_we     ({reg_div_we, reg_div_we, reg_div_we, reg_div_we}), | 
 | .reg_div_di     (UART_PRESCALER), | 
 | .reg_div_do     (), | 
 |  | 
 | .reg_dat_we     (uart_x_stb), | 
 | .reg_dat_re     (1'd0), | 
 | .reg_dat_di     ({24'd0, uart_x_dat}), | 
 | .reg_dat_do     (), | 
 | .reg_dat_wait   () | 
 | ); | 
 |  | 
 | // Debug | 
 | always @(posedge CLK) | 
 |     if (uart_x_stb) | 
 |         $display("%c", uart_x_dat); | 
 |  | 
 | endmodule | 
 |  |