Search code examples
verilogyosys

Getting "Warning: Driver-driver conflict" errors from yosys


I'm messing around with FPGAs and am running into some warnings that I sort of understand but don't know what's causing them. My understanding is there was a conflict of some kind and it is resolved but using a constant value. Though that will cause things to not work, which is what I'm seeing.

Warning: Driver-driver conflict for \controller.out_buff [1] between cell $flatten\alu.$procdff$1191.Q and constant 1'0 in cpu: Resolved using constant.
Warning: Driver-driver conflict for \controller.out_buff [1] between cell $auto$ff.cc:266:slice$1430.Q and constant 1'0 in cpu: Resolved using constant.
Warning: Driver-driver conflict for \controller.out_buff [1] between cell $flatten\pc.$procdff$1163.Q and constant 1'0 in cpu: Resolved using constant.
Warning: Driver-driver conflict for \controller.out_buff [1] between cell $flatten\register_a.$procdff$1161.Q and constant 1'0 in cpu: Resolved using constant.
Warning: Driver-driver conflict for \controller.out_buff [1] between cell $flatten\register_b.$procdff$1161.Q and constant 1'0 in cpu: Resolved using constant.
Warning: Driver-driver conflict for \controller.out_buff [1] between cell $flatten\register_instruction.$procdff$1161.Q and constant 1'0 in cpu: Resolved using constant.
Warning: Driver-driver conflict for \controller.out_buff [1] between cell $flatten\register_output.$procdff$1161.Q and constant 1'0 in cpu: Resolved using constant.

My issue is I don't know why there are the warnings, or how to fix them... I've included below my cpu.v, register.v and controller.v files below as four of the errors are related to the register and if I can figure that out I can figure the rest out, I hope.

What is causing the Driver-driver warnings? How do I fix it?

cpu.v

module cpu
(
    input i_clk,
    input i_reset,
    output [5:0] led
);

  wire [7:0] bus;

  wire register_a_read_n;
  wire register_a_write_n;

  wire register_b_read_n;
  wire register_b_write_n;

  wire register_instruction_read_n;
  wire register_instruction_write_n;
  wire [7:0] regiter_instruction_internal;

  wire register_out_write_n;
  wire [7:0] regiter_out_internal;

  wire register_mem_write_n;
  wire [7:0] regiter_mem_internal;

  wire programcounter_read_n;
  wire programcounter_write_n;
  wire programcounter_inc_n;

  wire alu_read_n;
  wire alu_subtract;
  wire [7:0] alu_input_a;
  wire [7:0] alu_input_b;

  wire [3:0] mem_address;
  wire mem_read_n;
  wire mem_write_n;

  wire [3:0] instruction;
  wire [3:0] instruction_argument;

  wire flag_c;
  wire flag_z;

  wire sys_clock;
  wire control_halt;

  assign led[5:0] = ~regiter_out_internal[5:0];
  assign mem_address[3:0] = regiter_mem_internal[3:0];
  assign instruction = regiter_instruction_internal[7:4];
  assign instruction_argument = regiter_instruction_internal[3:0];

  clock system_clock
  (
    .i_clk(i_clk),
    .i_halt(control_halt),
    .o_clk(sys_clock)
  );

  register register_a
  (
    .i_clk(sys_clock),
    .i_reset(i_reset),
    .i_read_n(register_a_read_n),
    .i_write_n(register_a_write_n),
    .io_bus(bus),
    .internal_data(alu_input_a)
  );

  register register_b
  (
    .i_clk(sys_clock),
    .i_reset(i_reset),
    .i_read_n(register_b_read_n),
    .i_write_n(register_b_write_n),
    .io_bus(bus),
    .internal_data(alu_input_b)
  );

  register register_instruction
  (
    .i_clk(sys_clock),
    .i_reset(i_reset),
    .i_read_n(register_instruction_read_n),
    .i_write_n(register_instruction_write_n),
    .io_bus(bus),
    .internal_data(regiter_instruction_internal)
  );

  register register_output
  (
    .i_clk(sys_clock),
    .i_reset(i_reset),
    .i_read_n(1'b1),
    .i_write_n(register_out_write_n),
    .io_bus(bus),
    .internal_data(regiter_out_internal)
  );

  register register_mem
  (
    .i_clk(sys_clock),
    .i_reset(i_reset),
    .i_read_n(1'b1),
    .i_write_n(register_mem_write_n),
    .io_bus(bus),
    .internal_data(regiter_mem_internal)
  );

  programcounter pc
  (
    .i_clk(sys_clock),
    .i_reset(i_reset),
    .i_read_n(programcounter_read_n),
    .i_write_n(programcounter_write_n),
    .i_inc_n(programcounter_inc_n),
    .io_bus(bus)
  );

  alu alu
  (
    .i_clk(sys_clock),
    .i_reset(i_reset),
    .i_read_n(alu_read_n),
    .i_subtract(alu_subtract),
    .i_data_a(alu_input_a),
    .i_data_b(alu_input_b),
    .o_flag_c(flag_c),
    .o_flag_z(flag_z),
    .o_bus(bus)
  );

  memory mem
  (
    .i_clk(sys_clock),
    .i_address(mem_address),
    .i_read_n(mem_read_n),
    .i_write_n(mem_write_n),
    .io_bus(bus)
  );

  controller controller
  (
    .i_clk(sys_clock),
    .i_reset(i_reset),
    .i_instruction(instruction),
    .i_instruction_argument(instruction_argument),
    .i_flag_c(flag_c),
    .i_flag_z(flag_z),
    .o_bus(bus),
    .o_halt(control_halt),
    .o_reg_mem_write_n(),
    .o_mem_read_n(mem_read_n),
    .o_mem_write_n(mem_write_n),
    .o_reg_instruction_read_n(),
    .o_reg_instruction_write_n(),
    .o_reg_a_read_n(register_a_read_n),
    .o_reg_a_write_n(register_a_write_n),
    .o_alu_read_n(alu_read_n),
    .o_alu_subtract(alu_subtract),
    .o_reg_b_read_n(register_b_read_n),
    .o_reg_b_write_n(register_b_write_n),
    .o_reg_out_write_n(register_out_write_n),
    .o_pc_read_n(programcounter_read_n),
    .o_pc_write_n(programcounter_write_n),
    .o_pc_inc_n(programcounter_inc_n)
  );

endmodule

register.v

module register
(
  i_clk,
  i_reset,
  i_read_n,
  i_write_n,
  io_bus,
  internal_data
);

  // Control signals
  input wire i_clk;
  input wire i_reset;
  input wire i_read_n;
  input wire i_write_n;

  // Inputs & Outputs
  inout wire [7:0] io_bus;
  output reg [7:0] internal_data;

  reg [7:0] bus_data;
  assign io_bus = bus_data;

  initial begin
    internal_data <= 8'b00000000;
  end

  wire  sen;
  assign sen = i_clk || i_reset;
  
  always @(posedge sen) begin
    if (i_reset == 1'b1) begin
      internal_data <= 8'b00000000;
      bus_data <= 8'bZZZZZZZZ;
    end else begin
      if (i_write_n == 1'b0) begin
        internal_data <= io_bus;
      end
      if (i_read_n == 1'b0) begin
        bus_data <= internal_data;
      end else begin
        bus_data <= 8'bZZZZZZZZ;
      end
    end
  end
endmodule

controller.v

module controller
(
  i_clk,
  i_reset,
  i_instruction,
  i_instruction_argument,
  i_flag_c,
  i_flag_z,
  o_bus,
  o_halt,
  o_reg_mem_write_n,
  o_mem_read_n,
  o_mem_write_n,
  o_reg_instruction_read_n,
  o_reg_instruction_write_n,
  o_reg_a_read_n,
  o_reg_a_write_n,
  o_alu_read_n,
  o_alu_subtract,
  o_reg_b_read_n,
  o_reg_b_write_n,
  o_reg_out_write_n,
  o_pc_read_n,
  o_pc_write_n,
  o_pc_inc_n
);

  // Control signals
  input wire i_clk;
  input wire i_reset;

  // Inputs & Outputs
  input wire [3:0] i_instruction;
  input wire [3:0] i_instruction_argument;
  input wire i_flag_c;
  input wire i_flag_z;
  inout wire [7:0] o_bus;
  output reg o_halt;
  output reg o_reg_mem_write_n;
  output reg o_mem_read_n;
  output reg o_mem_write_n;
  output reg o_reg_instruction_read_n;
  output reg o_reg_instruction_write_n;
  output reg o_reg_a_read_n;
  output reg o_reg_a_write_n;
  output reg o_alu_read_n;
  output reg o_alu_subtract;
  output reg o_reg_b_read_n;
  output reg o_reg_b_write_n;
  output reg o_reg_out_write_n;
  output reg o_pc_read_n;
  output reg o_pc_write_n;
  output reg o_pc_inc_n;

  // Internal
  reg [7:0] out_buff;
  integer cycle_step;
  integer instruction_step;

  assign o_bus = out_buff;

  initial begin
    cycle_step = 0;
    out_buff <= 8'bZZZZZZZZ;
    o_halt <= 1'b0;
    o_reg_mem_write_n <= 1'b1;
    o_mem_read_n <= 1'b1;
    o_mem_write_n <= 1'b1;
    o_reg_instruction_read_n <= 1'b1;
    o_reg_instruction_write_n <= 1'b1;
    o_reg_a_read_n <= 1'b1;
    o_reg_a_write_n <= 1'b1;
    o_alu_read_n <= 1'b1;
    o_alu_subtract <= 1'b0;
    o_reg_b_read_n <= 1'b1;
    o_reg_b_write_n <= 1'b1;
    o_pc_read_n <= 1'b1;
    o_pc_write_n <= 1'b1;
    o_pc_inc_n <= 1'b1;
  end

  wire  sen;
  assign sen = i_clk || i_reset;

  // Main controller loop
  always @(posedge sen) begin
    if (i_reset == 1'b1) begin
      cycle_step = 0;
      out_buff <= 8'bZZZZZZZZ;
      o_halt <= 1'b0;
      o_reg_mem_write_n <= 1'b1;
      o_mem_read_n <= 1'b1;
      o_mem_write_n <= 1'b1;
      o_reg_instruction_read_n <= 1'b1;
      o_reg_instruction_write_n <= 1'b1;
      o_reg_a_read_n <= 1'b1;
      o_reg_a_write_n <= 1'b1;
      o_alu_read_n <= 1'b1;
      o_alu_subtract <= 1'b0;
      o_reg_b_read_n <= 1'b1;
      o_reg_b_write_n <= 1'b1;
      o_pc_read_n <= 1'b1;
      o_pc_write_n <= 1'b1;
      o_pc_inc_n <= 1'b1;
    end else begin
      if (cycle_step == 0) begin
        // Load the PC contents into mem reg
        o_pc_read_n <= 1'b0;
        o_reg_mem_write_n <= 1'b0;
        o_reg_out_write_n <= 1'b0;

        cycle_step = 1;
      end

      if (cycle_step == 1) begin
        o_pc_read_n <= 1'b1;
        o_reg_mem_write_n <= 1'b1;
        o_reg_out_write_n <= 1'b1;

        // Load mem content into instruction reg
        o_mem_read_n <= 1'b0;
        o_reg_instruction_write_n <= 1'b0;

        // Inc the PC register
        o_pc_inc_n <= 1'b0;

        cycle_step = 2;
      end

      if (cycle_step == 2) begin
        o_mem_read_n <= 1'b1;
        o_reg_instruction_write_n <= 1'b1;
        o_pc_inc_n <= 1'b1;

        instruction_step = 0;
        cycle_step = 0;
      end

      // Instructions

      if (cycle_step == 99) begin
        if (i_instruction == 4'b0001) begin // LDA (Load A)
          if (instruction_step == 0) begin
            // set mem reg
            out_buff <= 8'b00000000;
            out_buff[3:0] <= i_instruction_argument;
            o_reg_mem_write_n <= 1'b1;

            instruction_step = 1;
          end

          if (instruction_step == 1) begin
            o_reg_mem_write_n <= 1'b0;
            out_buff <= 8'bZZZZZZZZ;

            // Load mem into A reg
            o_mem_read_n <= 1'b0;
            o_reg_a_write_n <= 1'b0;

            instruction_step = 2;
          end

          if (instruction_step == 2) begin
            o_mem_read_n <= 1'b1;
            o_reg_a_write_n <= 1'b1;

            // Finish instruction
            instruction_step = 0;
            cycle_step = 0;
          end
        end else if (i_instruction == 4'b0010) begin // LDB (Load B)
          if (instruction_step == 0) begin
            // set mem reg
            out_buff <= 8'b00000000;
            out_buff[3:0] <= i_instruction_argument;
            o_reg_mem_write_n <= 1'b1;

            instruction_step = 1;
          end

          if (instruction_step == 1) begin
            o_reg_mem_write_n <= 1'b0;
            out_buff <= 8'bZZZZZZZZ;

            // Load mem into B reg
            o_mem_read_n <= 1'b0;
            o_reg_b_write_n <= 1'b0;

            instruction_step = 2;
          end

          if (instruction_step == 2) begin
            o_mem_read_n <= 1'b1;
            o_reg_b_write_n <= 1'b1;

            // Finish instruction
            instruction_step = 0;
            cycle_step = 0;
          end
        end else if (i_instruction == 4'b0011) begin // LDO (Load Out)
          if (instruction_step == 0) begin
            // set mem reg
            out_buff <= 8'b00000000;
            out_buff[3:0] <= i_instruction_argument;
            o_reg_mem_write_n <= 1'b1;

            instruction_step = 1;
          end

          if (instruction_step == 1) begin
            o_reg_mem_write_n <= 1'b0;
            out_buff <= 8'bZZZZZZZZ;

            // Load mem into B reg
            o_mem_read_n <= 1'b0;
            o_reg_out_write_n <= 1'b0;

            instruction_step = 2;
          end

          if (instruction_step == 2) begin
            o_mem_read_n <= 1'b1;
            o_reg_out_write_n <= 1'b1;

            // Finish instruction
            instruction_step = 0;
            cycle_step = 0;
          end
        end else if (i_instruction == 4'b1111) begin // HLT (Halt)
          if (instruction_step == 0) begin
            // set halt signal
            o_halt <= 1'b1;

            // Finish instruction
            instruction_step = 0;
            cycle_step = 0;
          end
        end else begin
          // Finish instruction
          instruction_step = 0;
          cycle_step = 0;
        end
      end
    end
  end
endmodule

Solution

  • Synthesizable Verilog is a limited subset of the Verilog language. The Verilog language allows both synthesizable and non-synthesizable coding. The non-synthesizable coding is for behavior models, delays, test bench code, and to a limited extent analog behavior. Synthesis tools expect you to write your code within a certain style template. It is up the the synthesis tool to decide how to translate into logic cells, but they generally follow the same templates for flops, comb-logic, tri-state logic, etc.

    All of your @(posedge sen) should be @(posedge i_clk or posedge i_reset) for asynchronous reset or @(posedge i_clk) for synchronous reset. If you are targeting for FPGA, you should go for synchronous reset as most FPGA boards had limited (if any) flops with asynchronous that you are allowed to control. If you are targeting for ASIC, then typically either should work but depending on the standard cell library that you are mapping to.

    assign io_bus = bus_data; should be assign io_bus = (i_read_n == 1'b0) ? internal_data : 8'bZZZZZZZZ;. You may or may not want to flop the i_read_n depending on your design needs. Synthesis tools usually treat assigning X or Z to a register as don't care (ie: what ever is convenient or optimal for the synthesizer). This is different than driving high-impedance Z to a net/wire. This is an area where Verilog simulation and synthesis differ. The preferred approach is to use a tri-state operator in the net. Registers should generally be assigned to known states.

    The same tri-state assignment criteria is true for assign o_bus = out_buff;. I will let you figure out the signal to enable the driver.


    Other issues:
    You are mixing blocking (=) and non-blocking (<=) assignments. Generally blocking should be used to assign combination logic and non-blocking should be used to assign synchronous logic. Typically combination logic and synchronous logic should be in separate always blocks. There are save ways to mix blocking and non-blocking but most RTL designers and verification people are adamantly agents it has been the cause of simulation vs synthesis mismatch.

    If you are targeting for ASIC, get ride of the initial blocks. Most ASIC synthesizers will ignore initial blocks.

    Consideration:
    In the cpu.v you are using the more modern ANSI style header (available since IEEE1364-2001; aka Verilog-2001). But it in the other module you are using the legacy non-ANSI style header (required in IEEE1364-1995; aka Verilog-95). The advantage of ANSI style header is fewer lines of code and less change missing port or additional port without a port connections. For example, the register module header could be written as:

    module register
    (
      // Control signals
      input wire i_clk,
      input wire i_reset,
      input wire i_read_n,
      input wire i_write_n,
    
      // Inputs & Outputs
      inout wire [7:0] io_bus,
      output reg [7:0] internal_data
    );