`define RESERVED 4'b0000 `define request_block 4'b0001 `define ack_request 4'b0010 `define byte_there 4'b0011 `define start_transfer 4'b0100 `define done_transfer 4'b0101 `define done_block 4'b0111 `define start_IMDCT 4'b1100 `define done_IMDCT 4'b1110 //Just for semantical differences. I use `null for communication required // signals and `idle for saying that "we're not doing anything here." // (Eric) `define idle 4'b1111 `define null 4'b1111 `define down 1'b0 `define up 1'b1 `define no 1'b0 `define yes 1'b1 `define set 1'b1 `define unset 1'b0 `define done 1'b1 //For SEND_BYTE and READ_BYTE //if db is 0 go out on data //if db is A go out on ctrl to parent //if db is 7E read in on ctrl from parent //if db is 1 data direction register (ignore) `define ADDR_DATA 16'h0000 `define ADDR_CIN 16'h000a `define ADDR_COUT 16'h007e `define ADDR_DDR 16'h0001 (ignore) module router(reset,clk,from_parent,from_child_0,from_child_1,to_parent,to_child_0,to_child_1,data_parent,data_child_0,data_child_1,state_output); input reset; input clk; input [3:0] from_parent; input [3:0] from_child_0; input [3:0] from_child_1; output [3:0] to_parent; output [3:0] to_child_0; output [3:0] to_child_1; output [7:0] state_output; inout [7:0] data_parent; inout [7:0] data_child_0; inout [7:0] data_child_1; reg child_0_running,child_1_running,child_up_down,first_byte, do_IMDCT,IMDCT_child; wire [7:0] both_ctrl; reg last_child_run,we_data_parent,we_data_child_0,we_data_child_1,error_state,child_done; reg [3:0] to_parent,to_child_0,to_child_1,to_child_0_last, to_child_1_last,to_parent_last; reg [7:0] data_to_child_0,data_to_child_1,data_to_parent; reg [287:0] data_to_imdct; reg [6:0] debug_state_output; wire [6:0] debug_state; //The below will be removed when the imdct module is instantiated wire from_imdct; assign both_ctrl = {from_child_0,from_child_1}; //Write_enables are all asserted HIGH! assign data_child_0 = (we_data_child_0) ? data_to_child_0 : 8'bz; assign data_child_1 = (we_data_child_1) ? data_to_child_1 : 8'bz; assign data_parent = (we_data_parent) ? data_to_parent : 8'bz; //assign state_output = (error_state) ? {error_state,debug_state} : {error_state, debug_state}; //assign debug_state = (error_state) ? debug_state : debug_state_output; assign state_output = {error_state,debug_state_output}; /* A Router on power-up will: * 1) wait for reset to be de-asserted * 2) monitor its children for requested blocks/done_blocks * 3) as necessary forward these requests to its parent * 4) chec */ always @(posedge clk) begin if (reset)//reset is asserted LOW begin to_child_0_last <= to_child_0; to_child_1_last <= to_child_1; to_parent_last <= to_parent; //do_IMDCT is completly seperate from child_X_running //one child can be running (transferring data) at the same time // that the other is doing IMDCT if (do_IMDCT) begin //Do nothing for now. do_IMDCT <= `no; /* On assertion, should: * 1) begin read data sequence of byte_there's * 2) assert `null when done, and exit read data sequence * 3) start IMDCT process (seperate module) * 4) wait for IMDCT module to assert that it's done * 5) assert done_IMDCT to child when finished * 6) set do_IMDCT to `no */ end // if (do_IMDCT) //else if ( //We DON'T want to start_IMDCT if it is already running! //This isn't fair ATM, it just chooses child_0 if it's ready, // but it needs TO BE made fair at some point else if (from_child_0 == `start_IMDCT) begin do_IMDCT <= `yes; IMDCT_child <= 1'b0; @(posedge clk) data_to_imdct[287:280] <= data_child_0; //et all.. end else if (from_child_1 == `start_IMDCT) begin do_IMDCT <= `yes; IMDCT_child <= 1'b1; end if (from_imdct == `done) begin end // Note: There is a bug in this code that once child_0_running is set, // it is never unset. This is not an issue at the moment, but I will // hopefully remember to fix this before it becomes an issue. // -Eric if (child_0_running) begin to_child_1 <= `idle; we_data_child_1 <= 1'b1; //Be sure to uncomment this before enabling child_1 !! last_child_run <= 1'b0; //start or continue child_0 comm if (from_child_0 == `request_block) begin child_done <= 1'b0; child_up_down <= `down; we_data_parent <= 1'b0; we_data_child_0 <= 1'b0; if (from_parent == `idle) begin if (!error_state) begin debug_state_output <= 7'b0000001; end to_parent <= `request_block; to_child_0 <= `idle; end else if (from_parent == `ack_request) begin if (!error_state) begin debug_state_output <= 7'b0000010; end to_parent <= `null; to_child_0 <= `ack_request; end else begin $display("Invalid response by parent to `request_block ", from_parent); if (!error_state) begin error_state <= `set; debug_state_output <= 7'b1000001; end end end // if (from_child_0 == `request_block) else if (from_child_0 == `null) begin child_done <= child_done; we_data_parent <= 1'b0; if (from_parent == `byte_there) begin if (!error_state) begin debug_state_output <= 7'b0000011; end // tell child byte_there to_child_0 <= `byte_there; to_parent <= `idle; data_to_child_0 <= data_parent; we_data_child_0 <= 1'b1; end else if (from_parent == `done_transfer) begin if (!error_state) begin debug_state_output <= 7'b0000100; end //tell child done_transfer //also could preemptively tell parent // `done_transfer as well, since we're completly // child-driven but.. to_child_0 <= `done_transfer; to_parent <= `idle; we_data_child_0 <= 1'b0; end else if (from_parent == `null) begin if (!error_state) begin debug_state_output <= 7'b0000101; end to_child_0 <= `null; to_parent <= `null; we_data_child_0 <= 1'b0; if (child_done) begin child_0_running <= 1'b0; end end else begin if (!error_state) begin debug_state_output <= 7'b0000110; end //tell child the same thing as last time to_child_0 <= to_child_0_last; to_parent <= `null; we_data_child_0 <= 1'b0; end // else: !if(from_parent == `done_transfer) end // if (from_child_0 == `null) else if (from_child_0 == `byte_there) begin child_done <= child_done; if (child_up_down == `down) begin we_data_parent <= 1'b0; if (from_parent == `byte_there) begin if (!error_state) begin debug_state_output <= 7'b0000111; end to_child_0 <= `byte_there; to_parent <= `byte_there; //the below shouldn't actually matter, // but just in case.. data_to_child_0 <= data_parent; we_data_child_0 <= 1'b1; end else if (from_parent == `null) begin if (!error_state) begin debug_state_output <= 7'b0001000; end to_child_0 <= `null; to_parent <= `byte_there; //Wow, am I really that stupid to have not // done this before? apparently. we_data_child_0 <= 1'b1; //Note that we actually specify TWO byte // addresses, but since I don't see us wiring // up more than 256 leaves (actually 8 levels // of depth), I ignore the second byte and // just treat it as regular data for the time // being. if (first_byte) begin //when we shift out, that's what child // we have to send to, but since we're // child-driven, does that actually make // a difference when going down? data_to_child_0 <= data_parent >> 1; first_byte <= `unset; end else begin data_to_child_0 <= data_parent; end end else begin $display("Invalid from_parent on byte_there"); if (!error_state) begin error_state <= `set; debug_state_output <= 7'b1000010; end end end // if (child_up_down == `down) else if (child_up_down ==`up) begin //to_child_0 <= from_parent; we_data_child_0 <= 1'b0; if (from_parent == `byte_there) begin if (error_state == `unset) begin debug_state_output <= 7'b0001001; end to_child_0 <= `byte_there; to_parent <= `byte_there; //the below shouldn't actually matter, // but just in case.. data_to_parent <= data_child_0; we_data_parent <= 1'b1; end else if (from_parent == `null) begin if (!error_state) begin debug_state_output <= 7'b0001010; end to_child_0 <= `null; to_parent <= `byte_there; //Here too, that was dumb. data_to_parent <= data_child_0; we_data_parent <= 1'b1; end else if (from_parent == `start_transfer) begin if (!error_state) begin debug_state_output <= 7'b0001011; end to_child_0 <= `start_transfer; to_parent <= `byte_there; //Note that this should shift in the child # //which happens to be zero here data_to_parent <= data_child_0 << 1; we_data_parent <= 1'b1; end else begin $display("Invalid response from parent to byte_there ", from_parent); if (!error_state) begin error_state <= `set; debug_state_output <= 7'b1000011; end end end // if (child_up_down == 1'b1) else begin //I haven't a clue how a one bit number could // be anything other than one or zero, but... $display("Invalid child_up_down value of ", child_up_down); if (!error_state) begin error_state <= `set; debug_state_output <= 7'b1000100; end end end // if (from_child_0 == `byte_there) else if (from_child_0 == `done_transfer) begin we_data_parent <= 1'b0; we_data_child_0 <= 1'b0; child_done <= 1'b1; if (child_up_down == `down) begin if (from_parent == `done_transfer) begin if (!error_state) begin //For some reason, enabling this makes the router think it's // getting into a error state. I really should find the problem // here sometime, but it appears to work just fine ATM //Ideas??? //debug_state_output <= 7'b0001100; end to_child_0 <= `done_transfer; to_parent <= `done_transfer; end else if (from_parent == `null) begin if (!error_state) begin debug_state_output <= 7'b0001101; end to_child_0 <= `null; to_parent <= `done_transfer; end else begin $display("Invalid from_parent on done_transfer"); if (!error_state) begin error_state <= `set; debug_state_output <= 7'b1000101; end end end // if (child_up_down == `down) else if (child_up_down == `up) begin if (from_parent == `null) begin if (!error_state) begin debug_state_output <= 7'b0001110; end to_child_0 <= `null; to_parent <= `done_transfer; end else if (from_parent == `done_transfer) begin if (!error_state) begin debug_state_output <= 7'b0001111; end to_child_0 <= `done_transfer; to_parent <= `done_transfer; end end // if (child_up_down == `up) else begin //Again, I haven't a clue how a one bit number could // be anything other than one or zero, but... $display("Invalid child_up_down value of ", child_up_down); if (!error_state) begin error_state <= `set; debug_state_output <= 7'b1000110; end end end // if (from_child_0 == `done_transfer) // add possible responses for child upload here else if (from_child_0 == `done_block) begin child_up_down <= 1'b1; we_data_parent <= 1'b0; we_data_child_0 <= 1'b0; child_done <= 1'b0; if (from_parent == `idle) begin if (!error_state) begin debug_state_output <= 7'b0010000; end to_child_0 <= `idle; to_parent <= `done_block; end else if (from_parent == `start_transfer) begin if (!error_state) begin debug_state_output <= 7'b0010001; end to_child_0 <= `start_transfer; to_parent <= `done_block; end else begin $display ("invalid response from parent to done_block ",from_parent); if (!error_state) begin error_state <= `set; debug_state_output <= 7'b1000111; end end end // if (from_child_0 == `done_block) else begin $display("Invalid control by child 0", from_child_0); if (!error_state) begin error_state <= `set; debug_state_output <= 7'b1001000; end end end // if (child_0_running) else if (child_1_running) begin //child_1_running <= 1'b0; to_child_0 <= `idle; we_data_child_0 <= 1'b1; //Be sure to uncomment this before enabling child_1 !! last_child_run <= 1'b1; //start or continue child_1 comm if (from_child_1 == `request_block) begin child_done <= 1'b0; child_up_down <= `down; we_data_parent <= 1'b0; we_data_child_1 <= 1'b0; if (from_parent == `idle) begin if (!error_state) begin debug_state_output <= 7'b0100001; end to_parent <= `request_block; to_child_1 <= `idle; end else if (from_parent == `ack_request) begin if (!error_state) begin debug_state_output <= 7'b0100010; end to_parent <= `null; to_child_1 <= `ack_request; end else begin $display("Invalid response by parent to `request_block ", from_parent); if (!error_state) begin error_state <= `set; debug_state_output <= 7'b1100001; end end end // if (from_child_1 == `request_block) else if (from_child_1 == `null) begin child_done <= child_done; we_data_parent <= 1'b0; if (from_parent == `byte_there) begin if (!error_state) begin debug_state_output <= 7'b0100011; end // tell child byte_there to_child_1 <= `byte_there; to_parent <= `idle; data_to_child_1 <= data_parent; we_data_child_1 <= 1'b1; end else if (from_parent == `done_transfer) begin if (!error_state) begin debug_state_output <= 7'b0100100; end //tell child done_transfer //also could preemptively tell parent // `done_transfer as well, since we're completly // child-driven but.. to_child_1 <= `done_transfer; to_parent <= `idle; we_data_child_1 <= 1'b0; end else if (from_parent == `null) begin if (!error_state) begin debug_state_output <= 7'b0100101; end to_child_1 <= `null; to_parent <= `null; we_data_child_1 <= 1'b0; if (child_done) begin child_1_running <= 1'b0; end end else begin if (!error_state) begin debug_state_output <= 7'b0100110; end //tell child the same thing as last time to_child_1 <= to_child_1_last; to_parent <= `null; we_data_child_1 <= 1'b0; end // else: !if(from_parent == `done_transfer) end // if (from_child_1 == `null) else if (from_child_1 == `byte_there) begin child_done <= child_done; if (child_up_down == `down) begin we_data_parent <= 1'b0; if (from_parent == `byte_there) begin if (!error_state) begin debug_state_output <= 7'b0100111; end to_child_1 <= `byte_there; to_parent <= `byte_there; //the below shouldn't actually matter, // but just in case.. data_to_child_1 <= data_parent; we_data_child_1 <= 1'b1; end else if (from_parent == `null) begin if (!error_state) begin debug_state_output <= 7'b0101000; end to_child_1 <= `null; to_parent <= `byte_there; //Wow, am I really that stupid to have not // done this before? apparently. we_data_child_1 <= 1'b1; //Note that we actually specify TWO byte // addresses, but since I don't see us wiring // up more than 256 leaves (actually 8 levels // of depth), I ignore the second byte and // just treat it as regular data for the time // being. if (first_byte) begin //when we shift out, that's what child // we have to send to, but since we're // child-driven, does that actually make // a difference when going down? data_to_child_1 <= data_parent >> 1; first_byte <= `unset; end else begin data_to_child_1 <= data_parent; end end else begin $display("Invalid from_parent on byte_there"); if (!error_state) begin error_state <= `set; debug_state_output <= 7'b1100010; end end end // if (child_up_down == `down) else if (child_up_down ==`up) begin //to_child_1 <= from_parent; we_data_child_1 <= 1'b0; if (from_parent == `byte_there) begin if (error_state == `unset) begin debug_state_output <= 7'b0101001; end to_child_1 <= `byte_there; to_parent <= `byte_there; //the below shouldn't actually matter, // but just in case.. data_to_parent <= data_child_1; we_data_parent <= 1'b1; end else if (from_parent == `null) begin if (!error_state) begin debug_state_output <= 7'b0101010; end to_child_1 <= `null; to_parent <= `byte_there; //Here too, that was dumb. data_to_parent <= data_child_1; we_data_parent <= 1'b1; end else if (from_parent == `start_transfer) begin if (!error_state) begin debug_state_output <= 7'b0101011; end to_child_1 <= `start_transfer; to_parent <= `byte_there; //Note that this should shift in the child # //which happens to be zero here data_to_parent <= {data_child_1[6:0],1'b1};// << 1; we_data_parent <= 1'b1; end else begin $display("Invalid response from parent to byte_there ", from_parent); if (!error_state) begin error_state <= `set; debug_state_output <= 7'b1100011; end end end // if (child_up_down == 1'b1) else begin //I haven't a clue how a one bit number could // be anything other than one or zero, but... $display("Invalid child_up_down value of ", child_up_down); if (!error_state) begin error_state <= `set; debug_state_output <= 7'b1100100; end end end // if (from_child_1 == `byte_there) else if (from_child_1 == `done_transfer) begin we_data_parent <= 1'b0; we_data_child_1 <= 1'b0; child_done <= 1'b1; if (child_up_down == `down) begin if (from_parent == `done_transfer) begin if (!error_state) begin //For some reason, enabling this makes the router think it's // getting into a error state. I really should find the problem // here sometime, but it appears to work just fine ATM //Ideas??? //debug_state_output <= 7'b0001100; end to_child_1 <= `done_transfer; to_parent <= `done_transfer; end else if (from_parent == `null) begin if (!error_state) begin debug_state_output <= 7'b0101101; end to_child_1 <= `null; to_parent <= `done_transfer; end else begin $display("Invalid from_parent on done_transfer"); if (!error_state) begin error_state <= `set; debug_state_output <= 7'b1100101; end end end // if (child_up_down == `down) else if (child_up_down == `up) begin if (from_parent == `null) begin if (!error_state) begin debug_state_output <= 7'b0101110; end to_child_1 <= `null; to_parent <= `done_transfer; end else if (from_parent == `done_transfer) begin if (!error_state) begin debug_state_output <= 7'b0101111; end to_child_1 <= `done_transfer; to_parent <= `done_transfer; end end // if (child_up_down == `up) else begin //Again, I haven't a clue how a one bit number could // be anything other than one or zero, but... $display("Invalid child_up_down value of ", child_up_down); if (!error_state) begin error_state <= `set; debug_state_output <= 7'b1100110; end end end // if (from_child_1 == `done_transfer) // add possible responses for child upload here else if (from_child_1 == `done_block) begin child_up_down <= 1'b1; we_data_parent <= 1'b0; we_data_child_1 <= 1'b0; child_done <= 1'b0; if (from_parent == `idle) begin if (!error_state) begin debug_state_output <= 7'b0110000; end to_child_1 <= `idle; to_parent <= `done_block; end else if (from_parent == `start_transfer) begin if (!error_state) begin debug_state_output <= 7'b0110001; end to_child_1 <= `start_transfer; to_parent <= `done_block; end else begin $display ("invalid response from parent to done_block ",from_parent); if (!error_state) begin error_state <= `set; debug_state_output <= 7'b1100111; end end end // if (from_child_1 == `done_block) else begin $display("Invalid control by child 1", from_child_1); if (!error_state) begin error_state <= `set; debug_state_output <= 7'b1101000; end end end // if (child_1_running) else begin case(both_ctrl) {`RESERVED,`RESERVED},//If this hits after the initial reset, we have a problem {`idle,`idle}: {child_0_running, child_1_running,first_byte} <= 3'b000; {`request_block,`idle}, {`done_block,`idle}, {`request_block,`start_IMDCT}, {`done_block,`start_IMDCT}: //set_child_0(child_0_running,child_1_running); {child_0_running, child_1_running,first_byte} <= 3'b101; {`idle,`request_block}, {`idle,`done_block}, {`start_IMDCT,`request_block}, {`start_IMDCT,`done_block}: //set_child_1(child_0_running,child_1_running); {child_0_running, child_1_running,first_byte} <= 3'b011; {`request_block,`request_block}, {`request_block,`done_block}, {`done_block,`request_block}, {`done_block,`done_block}: //pick_child(child_0_running,child_1_running,last_child_run); begin:pick //could just do: //child_0_running <= last_child_run; //child_1_running <= ~last_child_run; //but that doesn't have error checking for x/z if (last_child_run == 1'b0) begin child_0_running <= 1'b0; child_1_running <= 1'b1; end else if (last_child_run == 1'b1) begin child_0_running <= 1'b1; child_1_running <= 1'b0; end else begin //Not that I'd know how a one bit number wouldn't // be either one or zero $display("Last_child_run has an invalid value! ",last_child_run); child_0_running <= 1'b0; child_1_running <= 1'b0; if (!error_state) begin error_state <= `set; debug_state_output <= 7'b1001001; end end // else: !if(last_child_run == 1'b1) end default: begin $display("Invalid Request Combination ",both_ctrl); if (!error_state) begin error_state <= `set; debug_state_output <= 7'b1001010; end end endcase // case(both_ctrl) end end else//if !(reset) begin child_0_running <= 1'b0; child_1_running <= 1'b0; last_child_run <= 1'b1; child_done <= 1'b0; to_child_0 <= `idle; to_child_1 <= `idle; to_parent <= `idle; we_data_child_0 <= 1'b0; we_data_child_1 <= 1'b0; we_data_parent <= 1'b0; to_child_0_last <= `idle; to_child_1_last <= `idle; to_parent_last <= `idle; do_IMDCT <= `no; error_state <= `unset; first_byte <= `set; debug_state_output <= 7'b0000000; end end task set_child_0; output child_0_running; output child_1_running; begin:set0 child_0_running <= 1'b1; child_1_running <= 1'b0; end endtask // set_child_0 task set_child_1; output child_0_running; output child_1_running; begin:set1 child_0_running <= 1'b0; child_1_running <= 1'b1; end endtask // set_child_1 //Make this do something better at some point task pick_child; output child_0_running; output child_1_running; input last_child_run; begin:pick if (last_child_run == 1'b0) begin child_0_running <= 1'b0; child_1_running <= 1'b1; end else if (last_child_run == 1'b1) begin child_0_running <= 1'b1; child_1_running <= 1'b0; end else begin $display("Last_child_run has an invalid value!"); child_0_running <= 1'b0; child_1_running <= 1'b0; end // else: !if(last_child_run == 1'b1) end // block: pick endtask // pick_child endmodule // router