Scoreboard for 2x2 router

Design details:
2 input ports with dst_addr, data as sequence item fields.
2 output ports that receive input packets.
any input port can send txn to any output port.
Following are the two approaches I am contemplating. Please let me know if both the methods are accurate.

example sequence item is as below:
Assuming there are 2 master agents one for each input port driving traffic and monitoring the interfaces.
Also assuming there are 2 slave agents one for each output port just monitoring interface.

class txn_item extends uvm_sequence_item 
     rand bit [1:0] addr;
     rand bit [15:0] data;
endclass

Method1:

scoreboard uses uvm_tlm_analysis_fifo

class router_scoreboard extends uvm_scoreboard
      `uvm_component_utils(router_scoreaboard)
      `uvm_tlm_analysis_fifo in1_fifo;
      `uvm_tlm_analysis_fifo in2_fifo;
      `uvm_tlm_analysis_fifo out1_fifo;
      `uvm_tlm_analysis_fifo out2_fifo;
      `uvm_analsyis_export #(txn_item) in1_export;
      `uvm_analsyis_export #(txn_item) in2_export;
      `uvm_analsyis_export #(txn_item) out1_export;
      `uvm_analsyis_export #(txn_item) out2_export;
       // not showing build_phase, new or connect_phase
       txn_item out1_q[$];
       txn_item out2_q[$];

      task run_phase();
           forever begin
                fork 
                   begin
                      in1_fifo.get(txn);
                      process_req(txn);
                   end
                   begin
                      in2_fifo.get(txn);
                      process_req(txn)
                   end
                   begin
                      out1_fifo.get(txn);
                      compare_results(txn);
                   end
                   begin
                       out2_fifo.get(txn);
                      compare_results(txn);
                   end
                join
           end
      endtask
      task process_req(txn_item txn)
           if(txn.addr inside out1 range)
              out1_q.push_back(txn)
           else
             out2_q.push_back(txn)
      endtask
      task compare_results(txn_item txn)
         if(txn.addr inside out1 range)
             compare(txn, out1_q.pop_front())
         else
             compare(txn, out1_q.pop_front())
      endtask
endclass

Method2:
scoreboard use uvm_analysis_imp and implements write functions.

class router_scoreboard extends uvm_scoreboard 
      `uvm_component_utils(router_scoreboard)
       `uvm_analysis_imp_decl(_in1)
       `uvm_analysis_imp_decl(_in2)
       `uvm_analysis_imp_decl(_out1)
       `uvm_analysis_imp_decl(_out2)
       uvm_analysis_imp#(router_scoreboard, ten_item) in1_export;
       uvm_analysis_imp#(router_scoreboard, ten_item) in2_export;
       uvm_analysis_imp#(router_scoreboard, ten_item) out1_export;
       uvm_analysis_imp#(router_scoreboard, ten_item) out2_export;
       txn_item exp_item_1[$];
       txn_item exp_item_2[$];
      // not showing new function or build phase
      function write_in1(txn_item txn);
            if(txn.addr inside range of out1) begin
                  exp_item_1.push_back(txn);
            end
            else begin
                 exp_item_2.push_back(txn);
            end
      endfunction

      function write_in2(txn_item txn);
            if(txn.addr inside range of out1) begin
                  exp_item_1.push_back(txn);
            end
            else begin
                 exp_item_2.push_back(txn);
            end
      endfunction

      function write_out1(txn_item txn);
            txn_item exp_txn;
            exp_txn = ex_item_1.pop_front();
           if(exp_txn.addr == txn.addr)
             //address match
          else
           // address mismatch
         if(exp_txn.data == txn.data)
            // data match
         else
            // data mismatch
      endfunction

      function write_out2(txn_item txn);
            txn_item exp_txn;
            exp_txn = ex_item_2.pop_front();
           if(exp_txn.addr == txn.addr)
             //address match
          else
           // address mismatch
         if(exp_txn.data == txn.data)
            // data match
         else
            // data mismatch
      endfunction
endclass

This scoreboard is assuming the order of output is same as order of input txn.

What is the question/problem here?

Just wanted to understand if both methods are correct. Which is a better over the other.

I would go with the second method.
Much cleaner and more methodological.

Without using fork and “forever begin…end” loop - not sure even whether this code works.
For example: the fork is of type fork…join, so all branches should end before next iteration of the loop will span again the fork…join.
If you receive 2 back2back transactions on input1 it won’t be sampled properly, because the first transaction on input1 will end the first branch and won’t be activated till all other branches will end.

Using fork… join_none would help resolve the back2back problem?

No, it won’t solve the problem.
This is why method#2 is better.
It uses TLM ports, which according to the UVM user-guide is the proper way.
Please go over it and the “UVM cookbook” by Verification Academy.