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