Special FIFO Register
Sharing data between two systems
“Special FIFO Register”
FIFO (First In First Out) is a storage register set used to send information between two systems. FIFOs make the system loosely coupled.
| There are two types of FIFO available in general, based on the clocks for reading and writing :
|
SYNC FIFO
“The two read/write Systems have the same clock”
Sync FIFO is a special register which can be read and written by either Software side (host) or Hardware side (Application logic). Both are running at same clock. So that the user can fetch the data from the FIFO as has been put in the FIFO. SYNC FIFO has two status flags Full flag says that the status of the FIFO is Full and more data cannot be written into it. Empty flag says that there is no data in the FIFO and it cannot be read.
| Optionally, there are two additional, configurable flags Almost Full Flag is a flag, user can configure with the value of choice to indicate before all available space of FIFO are filled.
Almost Empty Flag is a flag, user can configure with the value of his choice to notify that he is about to read all of the available space in the FIFO. |
ASYNC FIFO
“Two systems having different clocks”
ASYNC FIFO is the latest entry as it is an enhancement of the FIFO Register.
With async FIFO, we share the data between two clock domains. Property “type = async ” will give us access to share data between two different domains.
Properties used in IDS are
- “fifo = true/false”
- “type = sync/async”
- “fifo_depth = user defined”
- “fifo.width = user defined”
- “fifo.full = reg field/signal”
- “fifo.empty = reg field/signal”
- “fifo.almost_full_val = user defined”
- “fifo.almost_empty_val = user defined”
- “fifo.almost_full = reg field/signal”
- “fifo_almost_empty =reg field/signal”
Bigger regwidth registers in IDesignSpec
Bigger regwidth registers in IDesignSpec
IDesignSpec is an EDA tool that solves most of the designer’s problems, in minutes rather than hours. In every release, we work to make some improvements and enhancements to make our tool the World’s best. In this release, we did something that was asked by our customers to support registers having a width greater than the selected bus width. Although, supporting this particular feature required a lot of research and was a brainstorming exercise for our engineering team.
For quite a sometime, we had been putting off the implementation of register width greater than bus width as were searching for the best algorithm to support bigger regwidth registers that can take lesser time while reading and writing from the bus– for all combinations of registers, fields and busses.
When an IP is reused, the bus access width can change based on the bus it is connected to. Having reusable IPs allow SoC architects to explore various ways to connect them. The need for this feature arises when you want to create a register spec independent of the bus access width.
In different flavours of IDesignSpec i.e. IDS Word, IDS Excel and IDS Cal, bus width can be selected in Configure->Bus Width. While in IDS Batch, there is option “-bus_width <8|16|32|64>”. In addition to this, we also confirm that the regwidth of registers should be a multiple of the bus width.
Depending on the bus width, there would be n (regwidth divided by bus_width) wr_valids, rd_valids and offsets. Based on the value of n wr_valids, write occurs on the buffer signal for each of the field and same as that for the rd_valids, which is responsible for reading data.
Moreover, while supporting bigger regwidth registers, we made sure that there should not be any delay, as there might be a case when a field crossing its boundary, in that scenario there would be a write depending on the previous decode and present decode signal.
Here is an example:
This example will show how a register of 32 bit read and write data with bus_width of 8 bit. There are 4 wr_valids, rd_valids and offsets. These four offsets will turn on or off to four different decodes, and these decode when combines with rd_stb and wr_stb activate rd_valids and wr_valids respectively.
assign Reg1_wr_valid0 = Reg1_decode0 && wr_stb;
assign Reg1_wr_valid1 = Reg1_decode1 && wr_stb;
assign Reg1_wr_valid2 = Reg1_decode2 && wr_stb;
assign Reg1_wr_valid3 = Reg1_decode3 && wr_stb;
assign Reg1_rd_valid0 = Reg1_decode0 && rd_stb;
assign Reg1_rd_valid1 = Reg1_decode1 && rd_stb;
assign Reg1_rd_valid2 = Reg1_decode2 && rd_stb;
assign Reg1_rd_valid3 = Reg1_decode3 && rd_stb;
assign Reg1_enb = Reg1_wr_valid0;
assign Reg1_offset0 = block_offset+‘h0;
assign Reg1_offset1 = block_offset+‘h0 + ‘h1 ;
assign Reg1_offset2 = block_offset+‘h0 + ‘h2 ;
assign Reg1_offset3 = block_offset+‘h0 + ‘h3 ;
assign Reg1_decode0 = (address[block_name_address_width-1 : 0] == Reg1_offset0[block_name_address_width-1 : 0] ) ? 1’b1 : 1’b0;
assign Reg1_decode1 = (address[block_name_address_width-1 : 0] == Reg1_offset1[block_name_address_width-1 : 0] ) ? 1’b1 : 1’b0;
assign Reg1_decode2 = (address[block_name_address_width-1 : 0] == Reg1_offset2[block_name_address_width-1 : 0] ) ? 1’b1 : 1’b0;
assign Reg1_decode3 = (address[block_name_address_width-1 : 0] == Reg1_offset3[block_name_address_width-1 : 0] ) ? 1’b1 : 1’b0;
Similarly, while a field is writing through bus, same always block is used to write a complete field in two cycles when the field is crossing the bus boundary.
if (Reg1_wr_valid0) // FIELD : SW Write
begin
Reg1_Field_q[7 : 0] <= ( wr_data[7 : 0] & reg_enb[7 : 0] ) | (Reg1_Field_q[7 : 0] & (~reg_enb[7 : 0]));
end
if (Reg1_wr_valid1) // FIELD : SW Write
begin
Reg1_Field_q[15 : 8] <= ( wr_data[7 : 0] & reg_enb[7 : 0] ) | (Reg1_Field_q[15 : 8] & (~reg_enb[7 : 0]));
end
Finally, when a read occurs, there is a read back mux to read the bits from the field making 4 rd_data and then OR-ing those rd_datas in rd_data that is a bus signal.
assign Reg1_rd_data0 = Reg1_rd_valid0 ? {Reg1_Field_q[7 : 0]} : 8’b00000000;
assign Reg1_rd_data1 = Reg1_rd_valid1 ? {Reg1_Field_q[15 : 8]} : 8’b00000000;
assign Reg1_rd_data2 = Reg1_rd_valid2 ? {Reg1_Field2_q[7 : 0]} : 8’b00000000;
assign Reg1_rd_data3 = Reg1_rd_valid3 ? {Reg1_Field2_q[15 : 8]} : 8’b00000000;
assign Reg1_rd_data = Reg1_rd_data0 | Reg1_rd_data1 | Reg1_rd_data2 | Reg1_rd_data3;
We have supported almost all properties that work when the regwidth is equal to bus_width.
In Summary, we would like to share that now from IDesignSpec release version 6.6.0.0 bigger regwidth registers i.e. registers having width greater than the bus_width, are now supported in Verilog and soon it will be supported in VHDL, UVM and ARV too. Different properties that are supported earlier are supported with this new enhancements with just a few limitations. We always try to make our tools better with the help of our customers. We hope user will use this feature and provide us valuable feedback – that’s what keeps us going!
Regalign in IDesignSpec
Regalign
IDesignSpec is an EDA tool used to generate RTL code and other outputs for a given specification about the registers in a variety of flavors such as IDS Batch, IDS Word, IDS Excel and IDS Calc.
With constantly improving technology and valuable feedback from our customers, Agnisys Engineering team constantly keep IdesignSpec a step ahead with the addition some new features.
One of the best feature that we are now supporting register with less and equal width (register size) than bus width(configure -> Bus Width) with backward compatibility register width only equal to bus width.
To do so, the user have to use property value pair {addressing = regalign}.
What is regalign?
The regalign is an address mapping technique, which states
“The registers are packed so each register starting address is a multiple of its size(in Bytes). RegGroup are aligned according to individual register’s size”.
So from the definition of regalign,
Register with width 8 bits can have starting address
0,1, 2, 3, ………. Where 0, 1, … are byte number
Register with width 16 bits will have starting address
0, 2, 4, …………. Where 0, 2, … are byte number
Register with width 32 bits will have starting address
0, 4, 8, …………. Where 0, 4, … are byte number
For Example:
If we have 3-registers of width 8, 8, 16 with bus width 32 then read and write operation will work as:
8-bit register [0:7] | 8-bit register [8:15] | 16-bit register [16:31] |
All registers will be accessed in one clock cycle.
Template view:
RTL CODE :
:
:
Aligned offset and decode for Reg1
assign Reg1_offset = block_offset+’h0;
assign Reg1_decode = (address[Block1_address_width-1 : bus_bits] == Reg1_offset[Block1_address_width-1 : bus_bits] ) ? 1’b1 : 1’b0;
:
:
always @(posedge clk)
:
:
Aligned software write for Reg1
if (Reg1_wr_valid) // FLD : SW Write
begin
Reg1_Fld_q <= ( wr_data[7 : 0] & reg_enb[7 : 0] ) | (Reg1_Fld_q & (~reg_enb[7 : 0]));
end
end // sw_write_close
end end // always clk
:
:
assign Reg1_rd_data = Reg1_rd_valid ? {Reg1_Fld_q} : 8’b00000000;
:
:
Aligned offset and decode for Reg2
assign Reg2_offset = block_offset+’h1;
assign Reg2_decode = (address[Block1_address_width-1 : bus_bits] == Reg2_offset[Block1_address_width-1 : bus_bits] ) ? 1’b1 : 1’b0;
:
:
always @(posedge clk)
:
:
Aligned software write for Reg2
if (Reg2_wr_valid) // FLD : SW Write
begin
Reg2_Fld_q <= ( wr_data[15 : 8] & reg_enb[15 : 8] ) | (Reg2_Fld_q & (~reg_enb[15 : 8])); end
end // sw_write_close
end
end // always clk
:
:
assign Reg2_rd_data = Reg2_rd_valid ? {Reg2_Fld_q} : 8’b00000000;
:
:
Aligned offset and decode for Reg3
assign Reg3_offset = block_offset+’h2;
assign Reg3_decode = (address[Block1_address_width-1 : bus_bits] == Reg3_offset[Block1_address_width-1 : bus_bits] ) ? 1’b1 : 1’b0;
:
:
always @(posedge clk)
:
:
Aligned software write for Reg3
if (Reg3_wr_valid) // FLD : SW Write
begin
Reg3_Fld_q <= ( wr_data[31 : 16] & reg_enb[31 : 16] ) | (Reg3_Fld_q & (~reg_enb[31 : 16]));
end
end // sw_write_close
end
end // always clk
:
:
Reading aligned data from all register
assign Reg3_rd_data = Reg3_rd_valid ? {Reg3_Fld_q} : 16’b0000000000000000;
assign rd_data = {24’h0,Reg1_rd_data} | {16’h0,Reg2_rd_data,8’h0} | {Reg3_rd_data,16’h0} ;
:
:
We have supported all other IDS property with register width less than and equal to bus width.
Summary:
The above discussion presents multiple registers being accessed only in single clock cycle, enabling faster RTL design. The property ‘addressing’ with value ‘regalign’ are supported by IDesignSpec version ‘6.6.16.0’ onwards. Now it is only supported in Verilog but to support in VHDL, UVM, ARV etc. is in our road map.
As we have done in the past, we request your feedback and will continue to work hard to improve IDesignSpec.
Paged Register In IDesignSpec
Paged Register In IDS
In computer operating systems, paging is a memory management scheme by which a computer stores and retrieves data from secondary storage for use in main memory. In this scheme, the operating system retrieves data from secondary storage in same-size blocks called pages.
Paging is an important part of virtual memory implementation in modern operating systems, using secondary storage to let programs exceed the size of available physical memory.
Paged registers are often used in embedded systems. Paged register is a set of registers sharing same physical address and another selector register is used to decide which out of them is actually accessed. The main usage of Paged register in embedded systems is for context switching.
Properties In IDS we have two properties page_count and page_select for generating the page register. Property page_count shows the number of context registers and page_select for select line i.e selecting the context register. Properties used in IDS for using Paged Register are
|
Points to be noted
- page_select and page_count, both properties should exist together to specify a Paged Register.
- Field definition of all the paged registers will be same.
- Only one register among the paged registers is accessible at a time, both from hardware or software side, based on the selector value.
RTL Generated through IDesignSpec
Following example shows that register ‘select’ whose field ‘Fld’ is used as a select line for the page register i.e select_Fld_q[1:0] value is used to select the page register.
always @(posedge clk)
begin
if (!reset_l)
begin
case(select_Fld_q[1:0])
0 : Page_Fld_q_0 <= 32’d0;
1 : Page_Fld_q_1 <= 32’d0;
2 : Page_Fld_q_2 <= 32’d0;
3 : Page_Fld_q_3 <= 32’d0;
endcase
end
else
begin
if (Page_Fld_in_enb) // FLD : HW Write
begin
case(select_Fld_q[1:0])
0 : Page_Fld_q_0 <= Page_Fld_in;
1 : Page_Fld_q_1 <= Page_Fld_in;
2 : Page_Fld_q_2 <= Page_Fld_in;
3 : Page_Fld_q_3 <= Page_Fld_in;
endcase
end
else
begin
if (Page_wr_valid) // FLD : SW Write
begin
case(select_Fld_q[1:0])
0: Page_Fld_q_0 <= ( wr_data[31 : 0] & reg_enb[31 : 0] ) | (Page_Fld_q & (~reg_enb[31 : 0]));
1: Page_Fld_q_1 <= ( wr_data[31 : 0] & reg_enb[31 : 0] ) | (Page_Fld_q & (~reg_enb[31 : 0]));
2: Page_Fld_q_2 <= ( wr_data[31 : 0] & reg_enb[31 : 0] ) | (Page_Fld_q & (~reg_enb[31 : 0]));
3: Page_Fld_q_3 <= ( wr_data[31 : 0] & reg_enb[31 : 0] ) | (Page_Fld_q & (~reg_enb[31 : 0]));
endcase
end
end // sw_write_close
end
end // always clk
UVM Model
In UVM-RAL Model we have to add the page register and its different context based on select register on different address map. In this example, we have two 32 bit registers, if the page register is specified at 0x4 location, than Page[0] is mapped at 0x04 and all other context registers i.e Page[1], Page[2] and Page[3] are outside the address space range specify in RTL.
For verification point of view IDS adds a task called pagedWrite for verifying the page register based on the value in select register.
default_map.add_reg( select, ‘h0, “RW“);
foreach (Page[Page_i])
begin
default_map.add_reg(Page[Page_i],’h4 | Page_i << 3, “RW“);
end
select.clear_hdl_path();
select.add_hdl_path_slice(“select_Fld_q“, 0, 32);
foreach (regname[Page_i])
begin
Page[Page_i].clear_hdl_path();
Page[Page_i].add_hdl_path_slice($sformatf(“Page_Fld_q_[%0d]”, Page_i), 0, 32);
end
lock_model();
endfunction
task pagedWrite(uvm_reg_data_t count,uvm_reg_sequence parent_seq);
uvm_status_e status;
select.write(status, count, .path(UVM_FRONTDOOR), .map(default_map), .parent(parent_seq));
Page[count].write(status, 32’ha, .path(UVM_FRONTDOOR), .map(default_map), .parent(parent_seq));
Page[count].mirror(status,UVM_CHECK, .path(UVM_FRONTDOOR), .map(default_map), .parent(parent_seq));
endtask
Summary
We have shown how paged registers are described in IDesignSpec i.e IDSWord or IDSExcel, and their generated RTL and UVM Reg Model. UVM model is flexible enough to describe any quirky registers. We can change the model and the Register abstract layer according to verification needs.
Virtual register
VIRTUAL/ALTERNATE VIEW REGISTER
INTRODUCTION
We have often seen that Engineers require an “alternate view register”. Alternate view register basically consists of two registers at the same address location and based on the execution mode, one register is selected.
USAGE
Lets take an example:-
- Design has a 32bit RW control register at block offset 0.
- In a default “run” execution mode (modeA), the register is interpreted as having 4 8-bit fields. Each field controls the increment delta value for a corresponding counter. The increment delta value is added to 1 to get the actual increment value as the counter changes at every cycle during the run execution. Let’s call the fields {ctr3, ctr2,ctr1,ctr0} and the reset value is 0000_0000_0000_0000 which means the counters simply count by 1 (no additional increment value).
- In an alternate run execution mode (modeB), the counters are not being used so the same register is used by the DUT for a different purpose. In this case, the register is interpreted as 2 16-bit fields. One field is the row address and the other is the target column address for a single memory instruction. Let’s call the alternate view fields {row,col}. The default in this mode could also be all 0s: 00000000_00000000.
- If user run in modeA after writing 0000_0001_0000_0001 to the register, register will increment ctr0 and ctr2 by 2 and the other counters increment by 1.
- Now if user wants to run in modeB in the same simulation and want to target row 1 and col 1.User do NOT have to re-write the register because it already has the value 00000001_00000001. User should also be able to write in one mode and read the value back in the other mode so that he or she can see how the value will be viewed in the alternate mode.
- When user randomize or write a value in a particular mode, he would be able to refer constraints and relevant fields based on the mode.
- User want to be able to display the register showing the fields based on a mode. Same for writing, reading, getting fields, randomizing… all should be based on the current mode that is applied to the regmodel.
LOGICAL VIEW
IMPLEMENTATION
The solution of Alternate view register is based on virtual registers and modelling the physical register as a memory.We have mapped two virtual registers with single physical memory based on a mode variable.The mode variable can be set and read from the config_db.
Uvm model of above example:-
Counter is a regmodel of register in execution modeA and col_row is a register of modeB.
….
// Function : build
virtual function void build();
//create
counter = Block1_vreg1::type_id::create(“counter“);
col_row = Block1_vreg2::type_id::create(“col_row“);
mem = Block1_Reg1::type_id::create(“mem”);
//config
mem.configure(this,”inst.Stack”);
counter.configure(this, null,1);
col_row.configure(this, null,1);
….
While in the simulation, based on the execution mode, the virtual register is implemented.
In all the case, the transactions in the virtual register is basically on the memory.
….
If (mem != null) begin
If (mode==A) begin
vregs=blk.get_vreg_by_name(“counter”);
end
else begin
vregs= blk.get_vreg_by_name(“Col_row”);
end
vregs.implement(1,mem);
end
….
CONCLUSION
UVM model is flexible enough to describe any quirky registers. We can change the model and the Register abstract layer according to verification needs. The inclusion of the Extension Object for register methods provides a flexible way to communicate any type of data across the UVM RAL. We have shown how to create UVM reg model for alternate view registers.