【前端验证】通关寄存器与ral_model —— 25种常用寄存器类型全览

寄存器的属性分类

本文档对于寄存器的属性以synopsys相关文档以及ral_model生成模型时的识别方式为基准。通常讲可以归纳为以下三个方面:读写属性read-write access、写后值modified write value、读后操作read action。注意,这里指的都是软件的操作,对于硬件侧而言,寄存器无法感知到读行为,对于写行为一般允许通过hw_wen和hw_wdata进行操作。

通过这三方面的属性,可以精准的描述一个寄存器的行为,比如:

【前端验证】通关寄存器与ral_model —— 25种常用寄存器类型全览_第1张图片
在寄存器的xml描述中,采用如下的方式表示一个field的这三方面属性:

    read-write
    oneToSet
    clear

需要注意的是,access是必须要进行描述的,而modifiedWriteValue和readAction则不强制。modifiedWriteValue的缺省属性为总线数据写入,readAction的缺省属性为不改变寄存器值。

因此接下来先看一下这三个方面的属性都有哪些描述符。

Read-write Access

读写属性标记个某个寄存器(在此不区分寄存器reg和域field)是否可以被软件访问。

Access Read Write
read-write 返回寄存器值 参见Modified Write Value
read-only 返回寄存器值 总线返回error
write-only 总线返回error,总线读取值不可预期 参见 Modified Write Value
read-writeOnce 返回寄存器值 复位后只可写一次,写操作参见 Modified Write Value,后续写操作无效
writeOnce 总线返回error,总线读取值不可预期 复位后只可写一次,写操作参见 Modified Write Value,后续写操作无效

Modified Write Value

写后操作标记了某个寄存器在软件写操后数值的变化。

modifiedWriteValue 对应bit写0 对应bit写1
NA(缺省) 清0 置1
oneToClear 无影响 清0
oneToSet 无影响 置1
oneToToggle 无影响 翻转
zeroToClear 清0 无影响
zeroToSet 置1 无影响
zeroToToggle 翻转 无影响
clear 清0 清0
set 置1 置1

Read Action

读后行为标记了某个寄存器在软件读操后数值的变化。

readAction
NA(缺省) 无影响
clear 清0
set 置1

寄存器类型与RAL支持情况

结合以上三方面属性以及相关文档和ral_model的实际情况,可以得到下面的25种寄存器行为汇总和ral_model支持情况表格。

属性 行为 access modifiedWriteValue readAction ral是否支持
rw 软件可读可写 read-write NA NA
ro 软件可读,写返回总线报错 read-only NA NA
wo 软件可写,读数据报错 write-only NA NA
w1 仅复位后可写一次,读数据报错 read-writeOnce NA NA
w1c 写1清0,软件可读 read-write oneToClear NA
rc 软件读清零,写报错 read-only NA clear
rs 软件读置1,写报错 read-only NA set
wrc 软件可读写,读清零 read-write NA clear
wrs 软件可读写,读置1 read-write NA set
wc 软件可读写,写清零 read-write clear NA
ws 软件可读写,写置1 read-write set NA
wsrc 写置1,读清0 read-write set clear
wcrs 写清0,读置1 read-write clear set
w1s 写1置1,写0不变,软件可读 read-write oneToSet NA
w1t 写1翻转,写0不变,软件可读 read-write oneToToggle NA
w0c 写0清0,写1不变,软件可读 read-write zeroToClear NA
w0s 写0置1,写1不变,软件可读 read-write zeroToSet NA
w0t 写0翻转,软件可读 read-write zeroToToggle NA
w1src 写1置1,写0不变,读清0 read-write oneToSet clear
w1crs 写1清0,写0不变,读置1 read-write oneToClear set
w0src 写0置1,写1不变,读清0 read-write zeroToSet clear
w0crs 写0清0,写1不变,读置1 read-write zeroToClear set
woc 写清0,读错误 write-only clear NA
wos 写置1,读错误 write-only set NA
wo1 写置1,仅复位后第一次写有效,读错误 writeOnce NA NA

关键寄存器类型RTL实现

基于以上所有内容,对关键寄存器进行RTL实现。先确定一下寄存器的接口,个人是倾向于能够把寄存器的接口尽量的统一的,如有特殊情况再进行修改,因此规划的接口如下:

module reg_field #(
    parameter WD  = 32,
    parameter RST = {WD{1'b0}})
(
    input          clk,
    input          rst_n,

    input          st_wen,
    input          st_ren,
    input [WD -1:0]st_wdata,

    input          hw_wen,
    input [WD -1:0]hw_wdata,

    output[WD -1:0]rdata
);

endmodule

st代表软件操作,hw代表硬件操作。当然了软件操作更常见的信号是sel/en加wen的表示,不过我自己更喜欢wen和ren的方式所以就选了这样的接口规划。

而后需要说明的是,对于软件不可写或软件不可读的寄存器,个人倾向于在寄存器的上层进行控制。若一个寄存器不可写,那么st_wen不应该被上层调度模块拉起,且上层调度模块需要返回一个error状态给到总线。若一个寄存器不可读,那么st_ren同样不应该被拉起,且上层调度模块不应驱动总线上的读数据(使其保持旧值或高阻)同时返回error状态。基于这种思路,那么rw和wo就可以共用代码了,因为软件读的行为由上层处理。

RW/WO

//both for rw/wo
module reg_rw_field #(
    parameter WD  = 32,
    parameter RST = {WD{1'b0}})
(
    input          clk,
    input          rst_n,

    input          st_wen,
    input          st_ren,
    input [WD -1:0]st_wdata,

    input          hw_wen,
    input [WD -1:0]hw_wdata,

    output[WD -1:0]rdata
);
reg [WD -1:0]data_ff;

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        data_ff <= RST;
    else if(st_wen)
        data_ff <= st_wdata;
    else if(hw_wen)
        data_ff <= hw_wdata;
end

assign rdata = data_ff;

endmodule

RO

只读型寄存器是唯一没有寄存器实体的,直接将内部寄存器的值拉出来即可。

module reg_ro_field #(
    parameter WD  = 32,
    parameter RST = {WD{1'b0}})
(
    input          clk,
    input          rst_n,

    input [WD -1:0]hw_wdata,
    output[WD -1:0]rdata
);

assign rdata = hw_wdata;

endmodule

W1

module reg_w1_field #(
    parameter WD  = 32,
    parameter RST = {WD{1'b0}})
(
    input          clk,
    input          rst_n,

    input          st_wen,
    input          st_ren,
    input [WD -1:0]st_wdata,

    output[WD -1:0]rdata
);
reg [WD -1:0]data_ff;
reg lock_en;

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        data_ff <= RST;
    else if(!lock_en && st_wen)
        data_ff <= st_wdata;
end

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        lock_en <= 1'b0;
    else if(st_wen)
        lock_en <= 1'b1;
end

assign rdata = data_ff;

endmodule

W1C

module reg_w1c_field #(
    parameter WD  = 32,
    parameter RST = {WD{1'b0}})
(
    input          clk,
    input          rst_n,

    input          st_wen,
    input          st_ren,
    input [WD -1:0]st_wdata,

    input          hw_wen,
    input [WD -1:0]hw_wdata,

    output[WD -1:0]rdata
);
reg [WD -1:0]data_ff;

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        data_ff <= RST;
    else if(hw_wen)
        data_ff <= hw_wdata;
    else if(st_wen)
        data_ff <= (~st_wdata & data_ff);
end

assign rdata = data_ff;

endmodule

RC

注意,读清寄存器软件读后必须清零,而不是清为复位值。

module reg_rc_field #(
    parameter WD  = 32,
    parameter RST = {WD{1'b0}})
(
    input          clk,
    input          rst_n,

    input          st_wen,
    input          st_ren,
    input [WD -1:0]st_wdata,

    input          hw_wen,
    input [WD -1:0]hw_wdata,

    output[WD -1:0]rdata
);
reg [WD -1:0]data_ff;

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        data_ff <= RST;
    else if(hw_wen)
        data_ff <= hw_wdata;
    else if(st_ren)
        data_ff <= {WD{1'b0}};
end

assign rdata = data_ff;

endmodule

RS

module reg_rs_field #(
    parameter WD  = 32,
    parameter RST = {WD{1'b0}})
(
    input          clk,
    input          rst_n,

    input          st_wen,
    input          st_ren,
    input [WD -1:0]st_wdata,

    input          hw_wen,
    input [WD -1:0]hw_wdata,

    output[WD -1:0]rdata
);
reg [WD -1:0]data_ff;

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        data_ff <= RST;
    else if(hw_wen)
        data_ff <= hw_wdata;
    else if(st_ren)
        data_ff <= {WD{1'b1}};
end

assign rdata = data_ff;

endmodule

WRC

module reg_wrc_field #(
    parameter WD  = 32,
    parameter RST = {WD{1'b0}})
(
    input          clk,
    input          rst_n,

    input          st_wen,
    input          st_ren,
    input [WD -1:0]st_wdata,

    input          hw_wen,
    input [WD -1:0]hw_wdata,

    output[WD -1:0]rdata
);
reg [WD -1:0]data_ff;

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        data_ff <= RST;
    else if(hw_wen)
        data_ff <= hw_wdata;
    else if(st_wen)
        data_ff <= st_wdata;
    else if(st_ren)
        data_ff <=  {WD{1'b0}};
end

assign rdata = data_ff;

endmodule

WRS

module reg_wrs_field #(
    parameter WD  = 32,
    parameter RST = {WD{1'b0}})
(
    input          clk,
    input          rst_n,

    input          st_wen,
    input          st_ren,
    input [WD -1:0]st_wdata,

    input          hw_wen,
    input [WD -1:0]hw_wdata,

    output[WD -1:0]rdata
);
reg [WD -1:0]data_ff;

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        data_ff <= RST;
    else if(hw_wen)
        data_ff <= hw_wdata;
    else if(st_wen)
        data_ff <= st_wdata;
    else if(st_ren)
        data_ff <= {WD{1'b1}};
end

assign rdata = data_ff;

endmodule

WC

module reg_wc_field #(
    parameter WD  = 32,
    parameter RST = {WD{1'b0}})
(
    input          clk,
    input          rst_n,

    input          st_wen,
    input          st_ren,
    input [WD -1:0]st_wdata,

    input          hw_wen,
    input [WD -1:0]hw_wdata,

    output[WD -1:0]rdata
);
reg [WD -1:0]data_ff;

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        data_ff <= RST;
    else if(hw_wen)
        data_ff <= hw_wdata;
    else if(st_wen)
        data_ff <= {WD{1'b0}};
end

assign rdata = data_ff;

endmodule

WS

module reg_wc_field #(
    parameter WD  = 32,
    parameter RST = {WD{1'b0}})
(
    input          clk,
    input          rst_n,

    input          st_wen,
    input          st_ren,
    input [WD -1:0]st_wdata,

    input          hw_wen,
    input [WD -1:0]hw_wdata,

    output[WD -1:0]rdata
);
reg [WD -1:0]data_ff;

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        data_ff <= RST;
    else if(hw_wen)
        data_ff <= hw_wdata;
    else if(st_wen)
        data_ff <= {WD{1'b1}};
end

assign rdata = data_ff;

endmodule

WSRC

module reg_wsrc_field #(
    parameter WD  = 32,
    parameter RST = {WD{1'b0}})
(
    input          clk,
    input          rst_n,

    input          st_wen,
    input          st_ren,
    input [WD -1:0]st_wdata,

    input          hw_wen,
    input [WD -1:0]hw_wdata,

    output[WD -1:0]rdata
);
reg [WD -1:0]data_ff;

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        data_ff <= RST;
    else if(hw_wen)
        data_ff <= hw_wdata;
    else if(st_wen)
        data_ff <= {WD{1'b1}};
    else if(st_ren)
        data_ff <= {WD{1'b0}};
end

assign rdata = data_ff;

endmodule

WCRS

module reg_wcrs_field #(
    parameter WD  = 32,
    parameter RST = {WD{1'b0}})
(
    input          clk,
    input          rst_n,

    input          st_wen,
    input          st_ren,
    input [WD -1:0]st_wdata,

    input          hw_wen,
    input [WD -1:0]hw_wdata,

    output[WD -1:0]rdata
);
reg [WD -1:0]data_ff;

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        data_ff <= RST;
    else if(hw_wen)
        data_ff <= hw_wdata;
    else if(st_wen)
        data_ff <= {WD{1'b0}};
    else if(st_ren)
        data_ff <= {WD{1'b1}};
end

assign rdata = data_ff;

endmodule

W1S

module reg_field #(
    parameter WD  = 32,
    parameter RST = {WD{1'b0}})
(
    input          clk,
    input          rst_n,

    input          st_wen,
    input          st_ren,
    input [WD -1:0]st_wdata,

    input          hw_wen,
    input [WD -1:0]hw_wdata,

    output[WD -1:0]rdata
);
reg [WD -1:0]data_ff;

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        data_ff <= RST;
    else if(hw_wen)
        data_ff <= hw_wdata;
    else if(st_wen)
        data_ff <= data_ff | st_wdata;
end

assign rdata = data_ff;

endmodule

W1T

软件写1翻转,实际对应的就是原有值与写入值的亦或。

module reg_w1t_field #(
    parameter WD  = 32,
    parameter RST = {WD{1'b0}})
(
    input          clk,
    input          rst_n,

    input          st_wen,
    input          st_ren,
    input [WD -1:0]st_wdata,

    input          hw_wen,
    input [WD -1:0]hw_wdata,

    output[WD -1:0]rdata
);
reg [WD -1:0]data_ff;

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        data_ff <= RST;
    else if(hw_wen)
        data_ff <= hw_wdata;
    else if(st_wen)
        data_ff <= st_wdata ^ data_ff;
end

assign rdata = data_ff;

endmodule

其他ral_model不支持的类型我就没有都写完了,仅供参考吧。

你可能感兴趣的:(芯片前端设计,嵌入式硬件,verilog,芯片,systemverilog,fpga开发)