Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
16 years ago

Configure custom component with Nios?

Hello,

I started writing my own custom components for the SOPC builder. But I didn't understand yet, how I can configure my own component via Nios. I still worked with generic parameters, but now I want to give my component a register space which can be accessed via Nios.

How does it work?

Can you please give me a hint?

Best Regards!

tonib

5 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Ok, thanks! But how does it work exactly? Do I have to write a process which observs write transfers to my component and set a variable with the received data e.g.? Or is it possible to map addresses direct to variables?

    I want to use the memory interface to configure my component, so i have to store some "variables"...

    Thanks for your assistance!

    tonib
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    You have to write a process that waits for 'read' and 'write' control signals on the Avalon interface, yes.

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Ok thanks, but how is the general usage of storing configuration registers in own components? Do you use signals which are set and read by the process waiting for 'read' and 'write' control signals? Or how do you realize this storing of data?

    In my case I want to store some variables which control the behavior of my own component...

    Thanks!
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    You almost have it.

    1. Declare regs in your module to hold the parameters you need with the appropriate number of bits you require for each parameter. These are your "variables".

    2. Decide which address(es) will be associated with your parameter register(s).

    3. When a read or write control signal becomes active, decode the address lines (usually done with a case statement) and read or set the appropriate register.

    For example, to write to a parameter you might use "my_parameter_reg <= writedata;", or "my_parameter_reg[5:0] <= writedata[5:0];" if you have a configuration flags register to hold 6 boolean values. This is verilog syntax by the way.

    For reading, you might have something like "readdata_reg <= my_parameter_reg;", or "readdata_reg <= {26'b0, my_parameter_reg[5:0]};" and somewhere in your module "assign readdata = readdata_reg;" In this scenario, you would need 1 read waitstate to allow a specific parameter_reg to set the generic readdata_reg, which is then available to the readdata wires on the next clock.

    There are ways to avoid the waitstate, but you need to fairly complicated logical anding and oring operation to do so. Here is some essential snippets of code from one component I did:

    
    assign readdata = {32 {(address == 3'b000)}} & position |
                      {32 {(address == 3'b001)}} & r_counter_period |
                      {32 {(address == 3'b010)}} & r_step_pulse_length |
                      {32 {(address == 3'b011)}} & r_captured_position |
                      {32 {(address == 3'b100)}} & r_pulse_generator_value |
                      {32 {(address == 3'b111)}} & {r_position_has_been_captured, encoder_error, r_control_register};
     
     
    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            r_reset_position_has_been_captured <= 1'b1;
            r_reset_encoder_error <= 1'b1;
            r_set_counter <= 1'b1;
            r_control_register <= 10'b0;
            r_counter_period <= -1;
            r_step_pulse_length <= 16'hFF;
            r_new_counter_value <= 1'b0;
        end
        else begin
            if (chipselect) begin
                if (~write_n) begin
                    case (address)
                        3'b000: begin
                            r_new_counter_value <= writedata;
                            r_set_counter <= 1'b1;
                        end
                        3'b001: begin
                            r_counter_period <= writedata;
                        end
                       3'b010: begin
                           r_step_pulse_length <= writedata;
                       end
                       3'b011: begin
                           r_reset_position_has_been_captured <= 1'b1;
                       end
                       3'b100: begin
                           r_reset_encoder_error <= 1'b1;
                       end
                       3'b101: begin
                       end
                       3'b110: begin
                       end
                       3'b111: begin
                           r_control_register <= writedata;
                       end
                   endcase
               end // ~write_n
            end // chipselect
            else begin
                r_reset_encoder_error <= 1'b0;
                r_reset_position_has_been_captured <= 1'b0;
                r_set_counter <= 1'b0;
            end
        end // not in reset
    end