I continued to work on the Wishbone switch throughout the week.

First of all, I added some additional signal ports to the Wishbone switch I created last week. Those additional signals were described as follows, based on the Wishbone specification.

MASTER signals

  • SEL_O: It denoted the location of valid data.
  • WE_O: It would be asserted during WRITE cycles and negated during READ cycles.
  • CYC_O: It would be asserted throughout all bus cycles.

SLAVE signals

  • SEL_I: It denoted the location of valid data.
  • WE_I: It would be asserted during WRITE cycles and negated during READ cycles.
  • CYC_I: It would be asserted throughout all bus cycles.

As I would instantiate multiple switches at a later time, I assigned an address to each switch using a 4 bits hexadecimal value. The hexadecimal value would be used to identify a particular switch for the data to be passed to the data output array of an I/O device. The conditional statement was shown below.

if ((up_adr_i[31:30] == ADDR_PREFIX) & (up_adr_i[12+:4] == sw_addr)) begin
     ..
     io_dat_o <= up_dat_i;    // 32 bits data
end

else begin
     ..
     down_dat_o <= up_dat_i;    // 32 bits data
end

After completing the Wishbone switch, I created an AUTO_TEMPLATE to perform multiple instantiations, e.g. to instantiate 10 switches at a time. This greatly reduced my Verilog coding time as long as the indexes of wires were configured correctly. I spent some time to design the wiring between switches and draw a schematic design to connect the switches in a cascading style. It was very crucial to connect all wires correctly so that data could be passed from the upstream to either the I/O port or the downstream without any conflicts. It was a complicated task because there were a lot of signals to be considered in a Wishbone switch. I eventually managed to pass data from the Master to one of the I/O data output, depending on the address passed to the switches, i.e. up_dat_i. An example of AUTO_TEMPLATE was demonstrated below.

/* wb_switch AUTO_TEMPLATE(
  .up_dat_o(w@_dat_i[DATA_WIDTH-1:0]), .up_ack_o(w@_ack), .up_err_o(w@_err),
  .down_adr_o(w@”(% (+ 1 @) 17)”_adr[ADDR_WIDTH-1:0]),
  .down_dat_o(w@”(% (+ 1 @) 17)”_dat_o[DATA_WIDTH-1:0]),
  .down_we_o(w@”(% (+ 1 @) 17)”_we),
  .down_sel_o(w@”(% (+ 1 @) 17)”_sel[SEL_WIDTH-1:0]),
  .down_stb_o(w@”(% (+ 1 @) 17)”_stb),
  .down_cyc_o(w@”(% (+ 1 @) 17)”_cyc),
  .io_adr_o(io@_adr_o[ADDR_WIDTH-1:0]), .io_dat_o(io@_dat_o[DATA_WIDTH-1:0]),
  .io_we_o(io@_we_o), .io_sel_o(io@_sel_o[SEL_WIDTH-1:0]),
  .io_stb_o(io@_stb_o), .io_cyc_o(io@_cyc_o),
  .rst_i(rst_i), .clk_i(clk_i), .sw_addr(4’d@),
  .up_adr_i(w@_adr[ADDR_WIDTH-1:0]), .up_dat_i(w@_dat_o[DATA_WIDTH-1:0]),
  .up_we_i(w@_we), .up_sel_i(w@_sel[SEL_WIDTH-1:0]),
  .up_stb_i(w@_stb), .up_cyc_i(w@_cyc),
  .down_dat_i(w@”(% (+ 1 @) 17)”_dat_i[DATA_WIDTH-1:0]),
  .down_ack_i(w@”(% (+ 1 @) 17)”_ack),
  .down_err_i(w@”(% (+ 1 @) 17)”_err),
  .io_dat_i(io@_dat_i[DATA_WIDTH-1:0]), .io_ack_i(io@_ack_i), .io_err_i(io@_err_i),
  );
*/

In addition, I also created an AUTO_TEMPLATE for the Master and the Slave. I had to ensure the indexes of the wires matched the Wishbone switch or else they would not be working properly. An example of AUTO_TEMPLATE was shown below.

/* master AUTO_TEMPLATE(
.m_adr_o(r@_adr[ADDR_WIDTH-1:0]), .m_dat_o(r@_dat_o[DATA_WIDTH-1:0]),
.m_we_o(r@_we), .m_sel_o(r@_sel[SEL_WIDTH-1:0]),
.m_stb_o(r@_stb), .m_cyc_o(r@_cyc),
.int_dat_o(int@_dat_o[DATA_WIDTH-1:0]),
.int_ack_o(int@_ack_o), .int_err_o(int@_err_o),
.rst_i(rst_i), .clk_i(clk_i),
.m_dat_i(r@_dat_i[DATA_WIDTH-1:0]), .m_ack_i(r@_ack), .m_err_i(r@_err),
.int_adr_i(int@_adr_i[ADDR_WIDTH-1:0]), .int_dat_i(int@_dat_i[DATA_WIDTH-1:0]),
.int_we_i(int@_we_i), .int_sel_i(int@_sel_i[SEL_WIDTH-1:0]),
.int_stb_i(int@_stb_i), .int_cyc_i(int@_cyc_i),
);
*/

/* slave AUTO_TEMPLATE(
.s_dat_o(w@_dat_i[DATA_WIDTH-1:0]), .s_ack_o(w@_ack),
.s_err_o(w@_err),
.int_adr_o(int_adr_o[ADDR_WIDTH-1:0]), .int_dat_o(int_dat_o[DATA_WIDTH-1:0]),
.int_we_o(int_we_o), .int_sel_o(int_sel_o[SEL_WIDTH-1:0]),
.int_stb_o(int_stb_o),
.int_cyc_o(int_cyc_o),
.rst_i(rst_i), .clk_i(clk_i),
.s_adr_i(w@_adr[ADDR_WIDTH-1:0]), .s_dat_i(w@_dat_o[DATA_WIDTH-1:0]),
.s_we_i(w@_we), .s_sel_i(w@_sel[SEL_WIDTH-1:0]),
.s_stb_i(w@_stb), .s_cyc_i(w@_cyc),
.int_dat_i(int_dat_i[DATA_WIDTH-1:0]), .int_ack_i(int_ack_i),
);
*/

All in all, I would be focusing on testing the Wishbone switches next week to ensure there would be no errors. This was a productive week because I managed to complete the Wishbone switch and link some switches together in a cascading fashion.


1 Comment

Developing back-end – Blog@AESTE · 2019-07-29 at 12:02

[…] I worked on nextpnr to perform place and route for the wishbone switch. When I executed nextpnr-ice40, I received the following […]

Leave a Reply to Developing back-end – Blog@AESTECancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.