IC 設(shè)計(jì)工具篇 -- 寄存器模塊生成腳本設(shè)計(jì)過程(verilog 版)

簡(jiǎn)介

能讓電腦完成的就不要手寫了低剔,自動(dòng)生成寄存器模塊verilog代碼的腳本設(shè)計(jì)過程

不知道大家是否向我一樣账蓉,需要快速的實(shí)現(xiàn)模塊袱蚓。
我大部分寫的都是算法模塊钞啸,而且算法每次修改都特別大,除了控制部分可以復(fù)用以外其他都需要重新設(shè)計(jì)喇潘。
但是有些模塊還是有寫規(guī)律可循的体斩,比如寄存器部分。
不管算法如何改變寄存器的配置方式可以說都是差不多的颖低,那就可以讓電腦代替我來完成這部分工作了絮吵。

腳本功能

  • 直接生成寄存器模塊的verilog文件
  • 配置接口采用apb接口,32bit數(shù)據(jù)和16bit地址
  • 支持 RW忱屑、RO 類型的寄存器
  • 支持地址自動(dòng)分配
  • 支持地址和bit位粘連檢查

基礎(chǔ)知識(shí)

  • python
  • verilog

python現(xiàn)在主要有兩個(gè)大版本2.x 和 3.x 蹬敲,linux 現(xiàn)在大部分默認(rèn)還是python2暇昂,所以下面所有的都以python2為基礎(chǔ)
python 2.x 和 3.x 有些許不同,請(qǐng)大家注意
建議使用2.7和3.4及其以上版本

代碼格式

先定義下最后生成的代碼風(fēng)格(我就以我平時(shí)喜歡的風(fēng)格來設(shè)計(jì)了)
代碼中有下面兩類寄存器
1.可讀可寫的寄存器:base伴嗡,test
2.只讀寄存器:dbg

module Mbase_reg_cfg
(
  // clk / rst_n
   input                    i_clk
  ,input                    i_rst_n

  // apb port
  ,input                    i_psel
  ,input  [15:0]            i_paddr
  ,input                    i_penable
  ,input                    i_pwrite
  ,input  [31:0]            i_pwdata
  ,output [31:0]            o_prdata

  // output port
  ,output                   o_sw_base_0
  ,output [3:0]             o_sw_base_1
  ,output [3:0]             o_sw_tt_dbg_1
  ,output                   o_sw_tt_dbg_0

  // input port
  ,input  [3:0]             i_ro_dbg_1
  ,input  [6:0]             i_ro_dbg_0

);
//==========================================================
// apb bus ctrl                                 start/*{{{*/
//==========================================================
wire                        wr                             ;
wire                        rd                             ;
wire      [15:0]            addr                           ;
wire      [31:0]            wdata                          ;
reg       [31:0]            rdata                          ;

assign wr       = i_psel &  i_penable &  i_pwrite          ;
assign rd       = i_psel & ~i_penable & ~i_pwrite          ;
assign addr     = i_paddr                                  ;
assign wdata    = i_pwdata                                 ;
assign o_prdata = rdata                                    ;
//==========================================================
// apb bus ctrl                                   end/*}}}*/
//==========================================================

//==========================================================
// localparam                                   start/*{{{*/
//==========================================================
localparam BASE_ADDR                            = 16'h0000 ;
localparam DBG_ADDR                             = 16'h0004 ;
localparam TEST_ADDR                            = 16'h0008 ;
//==========================================================
// localparam                                     end/*}}}*/
//==========================================================

//==========================================================
// reg and wire                                 start/*{{{*/
//==========================================================

// write signal
wire        wr_base_w                                      ;
wire        wr_test_w                                      ;

// reg
reg  [31:0] reg_base_r                                     ;
reg  [31:0] reg_test_r                                     ;

// read data
wire [31:0] rdata_base_w                                   ;
wire [31:0] rdata_dbg_w                                    ;
wire [31:0] rdata_test_w                                   ;

//==========================================================
// reg and wire                                   end/*}}}*/
//==========================================================

//==========================================================
// write signal gen                             start/*{{{*/
//==========================================================
assign wr_base_w            = wr & (addr == BASE_ADDR     );
assign wr_test_w            = wr & (addr == TEST_ADDR     );
//==========================================================
// write signal gen                               end/*}}}*/
//==========================================================

//==========================================================
// base                                         start/*{{{*/
//==========================================================
localparam BASE_VALID_BIT                 = 32'h00_00_00_f1;
localparam BASE_DEFAULT                   = 32'h00_00_00_f1;

always@(posedge i_clk) begin
  if(i_rst_n == 1'd0) begin
    reg_base_r <= BASE_DEFAULT;
  end
  else if(wr_base_w) begin
    reg_base_r <= wdata & BASE_VALID_BIT;
  end
end

assign o_sw_base_0      = reg_base_r[0];
assign o_sw_base_1      = reg_base_r[7:4];

assign rdata_base_w = {
    24'd0
   ,o_sw_base_1
   ,3'd0
   ,o_sw_base_0
};
//==========================================================
// base                                           end/*}}}*/
//==========================================================

//==========================================================
// dbg                                          start/*{{{*/
//==========================================================
assign rdata_dbg_w = {
    14'd0
   ,i_ro_dbg_0
   ,3'd0
   ,i_ro_dbg_1
   ,4'd0
};
//==========================================================
// dbg                                            end/*}}}*/
//==========================================================

//==========================================================
// test                                         start/*{{{*/
//==========================================================
localparam TEST_VALID_BIT                 = 32'h80_00_00_f0;
localparam TEST_DEFAULT                   = 32'h00_00_00_00;

always@(posedge i_clk) begin
  if(i_rst_n == 1'd0) begin
    reg_test_r <= TEST_DEFAULT;
  end
  else if(wr_test_w) begin
    reg_test_r <= wdata & TEST_VALID_BIT;
  end
end

assign o_sw_tt_dbg_1    = reg_test_r[7:4];
assign o_sw_tt_dbg_0    = reg_test_r[31];

assign rdata_test_w = {
    o_sw_tt_dbg_0
   ,23'd0
   ,o_sw_tt_dbg_1
   ,4'd0
};
//==========================================================
// test                                           end/*}}}*/
//==========================================================

//==========================================================
// rdata                                        start/*{{{*/
//==========================================================
always@(posedge i_clk) begin
  if(i_rst_n == 1'd0) begin
    rdata <= 32'd0;
  end
  else if(rd) begin
    case(addr)
    BASE_ADDR              : rdata <= rdata_base_w         ;
    DBG_ADDR               : rdata <= rdata_dbg_w          ;
    TEST_ADDR              : rdata <= rdata_test_w         ;
    default                : rdata <= 32'd0                ;
    endcase
  end
  else begin
    rdata <= rdata;
  end
end
//==========================================================
// rdata                                          end/*}}}*/
//==========================================================

endmodule

生成用列表文件內(nèi)容

產(chǎn)生寄存器文件需要知道有那些寄存器和如何拼接
下面為產(chǎn)生上面寄存器文件所使用的列表文件格式
生成模塊名M<name>_reg_cfg
列表文件名<name>_reg_list
列表列表名<name>_reg_list

  • 如果列表文件和列表名不一致或是不匹配會(huì)出現(xiàn)問題
base_reg_list = [
{
  "name" : "base",
  "addr" : 0x0000,
  "type" : "RW",                # "RW" or "RO"
  "bit"  : [
    ["base_0", [0], 0x1],       # [寄存器名稱急波, 使用bit位, 默認(rèn)值]
    ["base_1", [7,4], 0xf],     # [寄存器名稱瘪校, 使用bit位澄暮, 默認(rèn)值]
  ]
},
{
  "name" : "dbg",
  # "addr" : 0x0004,            # 地址可以不顯示指定,默認(rèn)自增
  "type" : "RO",
  "bit"  : [
    ["dbg_1", [7,4]],
    ["dbg_0", [17,11], 0x0],    # 只讀寄存器默認(rèn)值不起作用
  ]
},
{
  "name" : "test",
  "addr" : 0x0008,
  # "type" : "RW",              # 類型可以不顯示指定阱扬,默認(rèn) "RW"
  "bit"  : [
    ["tt_dbg_1", [7,4]],        # 默認(rèn)值可以不顯示指定泣懊,默認(rèn) "0"
    ["tt_dbg_0", [31], 0x0],
  ]
},
]

腳本處理步驟

1.讀取寄存器列表
2.對(duì)沒有制定默認(rèn)值的地方進(jìn)行添加,沒有地址的使用前面進(jìn)行累加
3.檢查地址麻惶、bit位有無粘連
4.產(chǎn)生輸入輸出端口
5.產(chǎn)生localparam 地址內(nèi)容
6.產(chǎn)生后續(xù)會(huì)使用到的信號(hào)定義
7.產(chǎn)生寄存器寫使能邏輯
8.產(chǎn)生每個(gè)寄存器的寫過程和輸出信號(hào)拆分和讀取信號(hào)合并內(nèi)容
9.產(chǎn)生寄存器讀邏輯
10.合并上述內(nèi)容進(jìn)行輸出


腳本設(shè)計(jì)過程問題與關(guān)鍵點(diǎn)

1.讀取寄存器列表

主要讀取配置文件并生成腳本識(shí)別格式
為了省事馍刮,就不對(duì)寄存器列表進(jìn)行語法解析,而是使用python的exec函數(shù)
exec : 執(zhí)行字符串中的python語句

def get_reg_list(file_name):
  with open(file_name, "r") as f:
    data_str = f.readlines()
    data_str = "".join(data_str)

    _locals = locals()
    exec(data_str, globals(), _locals)
    data = _locals[file_name]

    return data

上面主要步驟

  • 打開文件并讀取全部?jī)?nèi)容用踩,將文件列表拼接為一個(gè)大的字符串
  • 執(zhí)行字符串中內(nèi)容渠退,將字符串中的寄存器列表返回

2.對(duì)沒有制定默認(rèn)值的地方進(jìn)行添加,沒有地址的使用前面進(jìn)行累加

為了后面代碼不會(huì)每次還判讀時(shí)候有指定脐彩,沒有指定用默認(rèn)值碎乃。
所以在給到后面處理時(shí)將沒有顯示指定的地方添加上默認(rèn)值,簡(jiǎn)化后面代碼處理
前面定義了地址默認(rèn)自增惠奸,類型默認(rèn)只讀梅誓,默認(rèn)值為0.
下面代碼有相應(yīng)的操作

def add_default(data):
  def_addr  = 0x0000
  def_type  = "RW"
  def_value = 0x0

  for reg in data:
    # add default addr
    try:
      def_addr = reg["addr"] + 4
    except:
      reg["addr"] = def_addr
      def_addr = reg["addr"] + 4

    # add default type
    try:
      reg["type"]
    except:
      reg["type"] = def_type

    for bit in reg["bit"]:
      # add default range
      if len(bit[1]) == 1:
        bit[1] = [bit[1][0],bit[1][0]]

      # add default value
      try:
        bit[2]
      except:
        bit.append(def_value)

上面代碼中這兩行不知道你有沒有想到為什么這么做。

      if len(bit[1]) == 1:
        bit[1] = [bit[1][0],bit[1][0]]

因?yàn)樵诩拇嫫髦挥幸粋€(gè)bit的情況下佛南,我們列表中只有一個(gè)值
為了將多bit和單bit統(tǒng)一梗掰,所以將單bit轉(zhuǎn)為和多bit相同的方式

3.檢查地址、bit位有無粘連

在設(shè)計(jì)過程中我一直有一個(gè)觀點(diǎn):人是最不靠譜的
在上面我們手動(dòng)需要寫的就是list文件
因?yàn)槭鞘謱懶峄兀瑳]有辦法保證100%正確及穗,所以需要添加適當(dāng)?shù)臋z查機(jī)制,確保正確性
常見的問題有幾點(diǎn):地址重疊绵载、bit重疊埂陆、bit超出范圍
下面代碼就是針對(duì)這幾點(diǎn)進(jìn)行的檢查

def check_overlap(data):
  err = 0
  
  # addr overlap check
  addr_list = []
  for reg in data:
    addr_list.append(reg["addr"])
  set_addr_list = list(set(addr_list))
  if len(addr_list) != len(set_addr_list):
    overlap_addr = [ addr for addr in set_addr_list if addr_list.count(addr) > 1]
    for addr in overlap_addr:
      print("Err  : 0x%08x addr overlap !!!" % addr)
      err = 1

  # bit overlap check
  for reg in data:
    bit_list = []
    for bit in reg["bit"]:
      bit_start = bit[1][1]
      bit_end   = bit[1][0]
      bit_list += range(bit_start,bit_end+1)
    set_bit_list = list(set(bit_list))
    if len([bit for bit in set_bit_list if bit >= 32]) > 0:
      print("Err  : reg %s addr 0x%08x bit out range !!!" % (reg['name'], reg['addr']))
      err = 1

    if len(bit_list) != len(set_bit_list):
      overlap_bit = [ bit for bit in set_bit_list if bit_list.count(bit) > 1]
      print("Err  : 0x%08x bit %s overlap !!!" % (reg['addr'], str(overlap_bit)))
      err = 1

  if err:
    sys.exit(1)

4.產(chǎn)生輸入輸出端口

接下來就該進(jìn)入正式的verilog代碼部分了
首先我們先確定需要產(chǎn)生的部分(下面內(nèi)容為上面代碼格式部分)

  // output port
  ,output                   o_sw_base_0
  ,output [3:0]             o_sw_base_1
  ,output [3:0]             o_sw_tt_dbg_1
  ,output                   o_sw_tt_dbg_0

  // input port
  ,input  [3:0]             i_ro_dbg_1
  ,input  [6:0]             i_ro_dbg_0

這部分是我們使用過程中需要的輸入輸出端口
所有的模塊我們都需要配置相應(yīng)的寄存器來確定工作模式或是開關(guān)
上面輸出口就是通過總線配置后的值
輸入一般為運(yùn)行后的輸出,或是debug用的
下面為詳細(xì)的產(chǎn)生代碼

def gen_io_port(data):
  io_str = []
  rw_list = [ reg for reg in data if reg['type'] == 'RW']
  ro_list = [ reg for reg in data if reg['type'] == 'RO']

  # output port
  io_str.append("  // output port\n")
  for reg in rw_list:
    for bit in reg['bit']:
      bit_range = bit[1]
      bit_len   = bit_range[0] - bit_range[1]

      if bit_len != 0:
        range_str = "[%d:0]" % bit_len
      else:
        range_str = ""

      bit_name_str = "o_sw_%s" % bit[0]

      io_str.append("  ,output %-17s %s\n" % (range_str, bit_name_str,))
  io_str.append("\n");

  # input port
  io_str.append("  // input port\n")
  for reg in ro_list:
    for bit in reg['bit']:
      bit_range = bit[1]
      bit_len   = bit_range[0] - bit_range[1]

      if bit_len != 0:
        range_str = "[%d:0]" % bit_len
      else:
        range_str = ""

      bit_name_str = "i_ro_%s" % bit[0]

      io_str.append("  ,input  %-17s %s\n" % (range_str, bit_name_str,))
  io_str.append("\n");

  return io_str

5.產(chǎn)生localparam 地址內(nèi)容

接下來就改產(chǎn)生地址信息了娃豹,這里使用lcalparam定義地址焚虱,然后使用
所以這里就只產(chǎn)生定義,具體使用在后面的寫邏輯生成
下面為需要產(chǎn)生的部分(下面內(nèi)容為上面代碼格式部分)

localparam BASE_ADDR                            = 16'h0000 ;
localparam DBG_ADDR                             = 16'h0004 ;
localparam TEST_ADDR                            = 16'h0008 ;

下面為產(chǎn)生代碼懂版。
這里沒有什么難點(diǎn)

def gen_localparam(data):
  localparam_str = []
  for reg in data:
    addr_name = "%s_ADDR" % reg['name'].upper()
    addr_str  = "16'h%04x" % reg['addr']

    localparam_str.append("localparam %-36s = %s ;\n" % (addr_name, addr_str,))

  return localparam_str

6.產(chǎn)生后續(xù)會(huì)使用到的信號(hào)定義

下面就是信號(hào)的定義部分
這里主要定義了:寫使能信號(hào)鹃栽、寄存器信號(hào)、讀數(shù)據(jù)信號(hào)

// write signal
wire        wr_base_w                                      ;
wire        wr_test_w                                      ;

// reg
reg  [31:0] reg_base_r                                     ;
reg  [31:0] reg_test_r                                     ;

// read data
wire [31:0] rdata_base_w                                   ;
wire [31:0] rdata_dbg_w                                    ;
wire [31:0] rdata_test_w                                   ;

寫使能和寄存器信號(hào)都是"RW"的才有躯畴,而讀數(shù)據(jù)信號(hào)是所有類型的都有
主要是因?yàn)?RO"的不需要寫民鼓,數(shù)據(jù)直接通過輸入進(jìn)來薇芝,只需要總線能讀取即可
下面為相應(yīng)產(chǎn)生部分

def gen_reg_wire(data):
  reg_wire_str = []
  rw_list = [ reg for reg in data if reg['type'] == 'RW']

  reg_wire_str.append("\n")
  # write signal
  reg_wire_str.append("http:// write signal\n")
  for reg in rw_list:
    wire_name = "wr_%s_w" % reg['name']

    reg_wire_str.append("wire        %-47s;\n" % wire_name)
  reg_wire_str.append("\n")

  # reg
  reg_wire_str.append("http:// reg\n")
  for reg in rw_list:
    reg_name = "reg_%s_r" % reg['name']

    reg_wire_str.append("reg  [31:0] %-47s;\n" % reg_name)
  reg_wire_str.append("\n")

  # read data
  reg_wire_str.append("http:// read data\n")
  for reg in data:
    wire_name = "rdata_%s_w" % reg['name']

    reg_wire_str.append("wire [31:0] %-47s;\n" % wire_name)
  reg_wire_str.append("\n")

  return reg_wire_str

7.產(chǎn)生寄存器寫使能邏輯

接下來就是產(chǎn)生寫使能邏輯

assign wr_base_w            = wr & (addr == BASE_ADDR     );
assign wr_test_w            = wr & (addr == TEST_ADDR     );

這里只需要產(chǎn)生RW類型的寫使能即可,RO不需要

def gen_write_signal(data):
  write_signal_str = []
  rw_list = [ reg for reg in data if reg['type'] == 'RW']

  for reg in rw_list:
    wire_name = "wr_%s_w" % reg['name']
    addr_name = "%s_ADDR" % reg['name'].upper()

    write_signal_str.append("assign %-20s = wr & (addr == %-14s);\n" % (wire_name, addr_name,))

  return write_signal_str

8.產(chǎn)生每個(gè)寄存器的寫過程和輸出信號(hào)拆分和讀取信號(hào)合并內(nèi)容

接下來就是最主要的部分了
寄存器的讀寫丰嘉、輸出連接恩掷、讀拼接都是在這里做的
下面為兩類寄存器生成的最終生成內(nèi)容(生成的注釋中有vim識(shí)別的折疊,這是個(gè)人習(xí)慣)

//==========================================================
// base                                         start/*{{{*/
//==========================================================
localparam BASE_VALID_BIT                 = 32'h00_00_00_f1;
localparam BASE_DEFAULT                   = 32'h00_00_00_f1;

always@(posedge i_clk) begin
  if(i_rst_n == 1'd0) begin
    reg_base_r <= BASE_DEFAULT;
  end
  else if(wr_base_w) begin
    reg_base_r <= wdata & BASE_VALID_BIT;
  end
end

assign o_sw_base_0      = reg_base_r[0];
assign o_sw_base_1      = reg_base_r[7:4];

assign rdata_base_w = {
    24'd0
   ,o_sw_base_1
   ,3'd0
   ,o_sw_base_0
};
//==========================================================
// base                                           end/*}}}*/
//==========================================================

//==========================================================
// dbg                                          start/*{{{*/
//==========================================================
assign rdata_dbg_w = {
    14'd0
   ,i_ro_dbg_0
   ,3'd0
   ,i_ro_dbg_1
   ,4'd0
};
//==========================================================
// dbg                                            end/*}}}*/
//==========================================================

下面代碼內(nèi)容較多供嚎,對(duì)照上面生成內(nèi)容看會(huì)更好

def gen_reg(data):
  reg_str = []
  for reg in data:
    reg_str.append("http://==========================================================\n")
    reg_str.append("http:// %-44s start/*{{{*/\n" % reg['name'])
    reg_str.append("http://==========================================================\n")

    reg_name       = "reg_%s_r"     % reg['name']
    value_bit_name = "%s_VALID_BIT" % reg['name'].upper()
    default_name   = "%s_DEFAULT"   % reg['name'].upper()
    write_name     = "wr_%s_w"      % reg['name']
    rdata_name     = "rdata_%s_w"   % reg['name']
    if reg['type'] == 'RW':
      # localparam
      value_bit = 0
      default   = 0
      for bit in reg['bit']:
        bit_range = bit[1]
        bit_def   = bit[2]
        bit_start = bit_range[1]
        bit_end   = bit_range[0]
        bit_len   = bit_end - bit_start + 1
        value_bit |= (((2**bit_len) - 1) << bit_start)
        default   |= bit_def << bit_start

      value_bit_str = "%08x" % value_bit
      default_str   = "%08x" % default

      value_bit_str = "_".join([ value_bit_str[i*2:i*2+2] for i in range(4)])
      default_str   = "_".join([ default_str[i*2:i*2+2] for i in range(4)])

      reg_str.append("localparam %-30s = 32'h%s;\n" % (value_bit_name, value_bit_str))
      reg_str.append("localparam %-30s = 32'h%s;\n" % (default_name, default_str))
      reg_str.append("\n")

      # reg function
      reg_str.append("always@(posedge i_clk) begin\n" )
      reg_str.append("  if(i_rst_n == 1'd0) begin\n"  )
      reg_str.append("    %s <= %s;\n"                % (reg_name, default_name,))
      reg_str.append("  end\n"                        )
      reg_str.append("  else if(%s) begin\n"          % write_name)
      reg_str.append("    %s <= wdata & %s;\n"        % (reg_name, value_bit_name,))
      reg_str.append("  end\n"                        )
      reg_str.append("end\n"                          )
      reg_str.append("\n"                             )

      # output
      for bit in reg['bit']:
        output_name = "o_sw_%s" % bit[0]
        bit_range   = bit[1]
        bit_start   = bit_range[1]
        bit_end     = bit_range[0]
        bit_len     = bit_end - bit_start + 1

        if bit_len > 1:
          bit_range_str = "[%d:%d]" % (bit_end, bit_start)
        else:
          bit_range_str = "[%d]" % bit_start

        reg_str.append("assign %-16s = %s%s;\n" % (output_name, reg_name, bit_range_str,))
      reg_str.append("\n")

    # rdata
    bit_index  = 0
    rdata_list = []
    for bit in reg['bit']:
      bit_range   = bit[1]
      bit_start   = bit_range[1]
      bit_end     = bit_range[0]

      if bit_index != bit_start:
        rdata_list.append("%d'd0" % (bit_start - bit_index))
      if reg['type'] == "RW":
        rdata_list.append("o_sw_%s" % bit[0])
      else:
        rdata_list.append("i_ro_%s" % bit[0])
      bit_index = bit_end + 1
    if bit_index != 32:
      rdata_list.append("%d'd0" % (32 - bit_index))

    reg_str.append("assign %s = {\n" % rdata_name)
    reg_str.append("    " + "\n   ,".join(rdata_list[::-1]) + "\n")
    reg_str.append("};\n")

      
    reg_str.append("http://==========================================================\n")
    reg_str.append("http:// %-44s   end/*}}}*/\n" % reg['name'])
    reg_str.append("http://==========================================================\n")
    reg_str.append("\n")

  return reg_str

首先產(chǎn)生需要一些名稱
產(chǎn)生默認(rèn)值、可寫bit 這兩個(gè)localparam
產(chǎn)生寄存器寫的always
產(chǎn)生輸出信號(hào)的連接
產(chǎn)生輸出信號(hào)的拼接峭状,這里RW拼接的是o_sw_* 而RO拼接的是i_ro_*

9.產(chǎn)生寄存器讀邏輯

這可以說已經(jīng)是最后了
前面大部分邏輯都生成了克滴,就差能讓總線讀取到的邏輯了

always@(posedge i_clk) begin
  if(i_rst_n == 1'd0) begin
    rdata <= 32'd0;
  end
  else if(rd) begin
    case(addr)
    BASE_ADDR              : rdata <= rdata_base_w         ;
    DBG_ADDR               : rdata <= rdata_dbg_w          ;
    TEST_ADDR              : rdata <= rdata_test_w         ;
    default                : rdata <= 32'd0                ;
    endcase
  end
  else begin
    rdata <= rdata;
  end
end

這里恒簡(jiǎn)單,因?yàn)榍懊嬉呀?jīng)將信號(hào)拼接好了优床,這里直接使用即可

def gen_rdata(data):
  rdata_str = []
  for reg in data:
    addr_name  = "%s_ADDR"    % reg['name'].upper()
    rdata_name = "rdata_%s_w" % reg['name']

    rdata_str.append("    %-22s : rdata <= %-21s;\n" % (addr_name, rdata_name,))
    
  return rdata_str

10.合并上述內(nèi)容進(jìn)行輸出

上面產(chǎn)生完所有邏輯內(nèi)容劝赔,這里就只需要將所有內(nèi)容拼接起來
下面代碼雖然長(zhǎng),但其實(shí)沒有什么內(nèi)容胆敞。

def gen_reg_file(
    mode_name,
    io_str,
    localparam_str,
    reg_wire_str,
    write_signal_str,
    reg_str,
    rdata_str,
    ):
  with open("../reg_file/%s_reg_cfg.v" % mode_name, "w") as f:
    f.write("module M%s_reg_cfg\n" % mode_name                              )
    f.write("(\n"                                                           )
    f.write("  // clk / rst_n\n"                                            )
    f.write("   input                    i_clk\n"                           )
    f.write("  ,input                    i_rst_n\n"                         )
    f.write("\n"                                                            )
    f.write("  // apb port\n"                                               )
    f.write("  ,input                    i_psel\n"                          )
    f.write("  ,input  [15:0]            i_paddr\n"                         )
    f.write("  ,input                    i_penable\n"                       )
    f.write("  ,input                    i_pwrite\n"                        )
    f.write("  ,input  [31:0]            i_pwdata\n"                        )
    f.write("  ,output [31:0]            o_prdata\n"                        )
    f.write("\n"                                                            )
    f.write("".join(io_str))
    f.write(");\n"                                                          )
    f.write("http://==========================================================\n")
    f.write("http:// apb bus ctrl                                 start/*{{{*/\n")
    f.write("http://==========================================================\n")
    f.write("wire                        wr                             ;\n")
    f.write("wire                        rd                             ;\n")
    f.write("wire      [15:0]            addr                           ;\n")
    f.write("wire      [31:0]            wdata                          ;\n")
    f.write("reg       [31:0]            rdata                          ;\n")
    f.write("\n"                                                            )
    f.write("assign wr       = i_psel &  i_penable &  i_pwrite          ;\n")
    f.write("assign rd       = i_psel & ~i_penable & ~i_pwrite          ;\n")
    f.write("assign addr     = i_paddr                                  ;\n")
    f.write("assign wdata    = i_pwdata                                 ;\n")
    f.write("assign o_prdata = rdata                                    ;\n")
    f.write("http://==========================================================\n")
    f.write("http:// apb bus ctrl                                   end/*}}}*/\n")
    f.write("http://==========================================================\n")
    f.write("\n"                                                            )
    f.write("http://==========================================================\n")
    f.write("http:// localparam                                   start/*{{{*/\n")
    f.write("http://==========================================================\n")
    f.write("".join(localparam_str))
    f.write("http://==========================================================\n")
    f.write("http:// localparam                                     end/*}}}*/\n")
    f.write("http://==========================================================\n")
    f.write("\n"                                                            )
    f.write("http://==========================================================\n")
    f.write("http:// reg and wire                                 start/*{{{*/\n")
    f.write("http://==========================================================\n")
    f.write("".join(reg_wire_str))
    f.write("http://==========================================================\n")
    f.write("http:// reg and wire                                   end/*}}}*/\n")
    f.write("http://==========================================================\n")
    f.write("\n"                                                            )
    f.write("http://==========================================================\n")
    f.write("http:// write signal gen                             start/*{{{*/\n")
    f.write("http://==========================================================\n")
    f.write("".join(write_signal_str))
    f.write("http://==========================================================\n")
    f.write("http:// write signal gen                               end/*}}}*/\n")
    f.write("http://==========================================================\n")
    f.write("\n"                                                            )
    f.write("".join(reg_str))
    f.write("http://==========================================================\n")
    f.write("http:// rdata                                        start/*{{{*/\n")
    f.write("http://==========================================================\n")
    f.write("always@(posedge i_clk) begin\n"                                )
    f.write("  if(i_rst_n == 1'd0) begin\n"                                 )
    f.write("    rdata <= 32'd0;\n"                                         )
    f.write("  end\n"                                                       )
    f.write("  else if(rd) begin\n"                                         )
    f.write("    case(addr)\n"                                              )
    f.write("".join(rdata_str))
    f.write("    default                : rdata <= 32'd0                ;\n")
    f.write("    endcase\n"                                                 )
    f.write("  end\n"                                                       )
    f.write("  else begin\n"                                                )
    f.write("    rdata <= rdata;\n"                                         )
    f.write("  end\n"                                                       )
    f.write("end\n"                                                         )
    f.write("http://==========================================================\n")
    f.write("http:// rdata                                          end/*}}}*/\n")
    f.write("http://==========================================================\n")
    f.write("\n"                                                            )
    f.write("endmodule\n"                                                   )

    f.close()

結(jié)尾

在工作過程中有許多的事着帽,而且IC這一行容錯(cuò)率非常低,稍微一個(gè)bug就可以是流片失斠撇恪(FPGA的除外)
而我一直奉行<人是最不靠譜的>觀點(diǎn)仍翰。而工作后會(huì)發(fā)現(xiàn)有很多的工具就是專門為了幫助人們找錯(cuò)誤的,仿真就是其一观话。
然而工具使用的在熟練予借,也是需要花費(fèi)不少時(shí)間的。
所以提高效率和準(zhǔn)確性就是流程化频蛔,并且自動(dòng)化

下面為完整的腳本

#!/bin/env python
import os
import sys

# ==========================================================
#  get reg list                                    start#{{{
# ==========================================================
def get_reg_list(file_name):
  try:
    with open(file_name, "r") as f:
      data_str = f.readlines()
      data_str = "".join(data_str)

      _locals = locals()
      exec(data_str, globals(), _locals)
      data = _locals[file_name]

      return data
  except:
    print("open file %s err" % file_name)
    sys.exit(1)
# ==========================================================
#  get reg list                                      end#}}}
# ==========================================================

# ==========================================================
#  add default                                     start#{{{
# ==========================================================
def add_default(data):
  def_addr  = 0x0000
  def_type  = "RW"
  def_value = 0x0

  for reg in data:
    # add default addr
    try:
      def_addr = reg["addr"] + 4
    except:
      reg["addr"] = def_addr
      def_addr = reg["addr"] + 4

    # add default type
    try:
      reg["type"]
    except:
      reg["type"] = def_type

    for bit in reg["bit"]:
      # add default range
      if len(bit[1]) == 1:
        bit[1] = [bit[1][0],bit[1][0]]

      # add default value
      try:
        bit[2]
      except:
        bit.append(def_value)
# ==========================================================
#  add default                                       end#}}}
# ==========================================================

# ==========================================================
#  check overlap                                   start#{{{
# ==========================================================
def check_overlap(data):
  err = 0
  
  # addr overlap check
  addr_list = []
  for reg in data:
    addr_list.append(reg["addr"])
  set_addr_list = list(set(addr_list))
  if len(addr_list) != len(set_addr_list):
    overlap_addr = [ addr for addr in set_addr_list if addr_list.count(addr) > 1]
    for addr in overlap_addr:
      print("Err  : 0x%08x addr overlap !!!" % addr)
      err = 1

  # bit overlap check
  for reg in data:
    bit_list = []
    for bit in reg["bit"]:
      bit_start = bit[1][1]
      bit_end   = bit[1][0]
      bit_list += range(bit_start,bit_end+1)
    set_bit_list = list(set(bit_list))
    if len([bit for bit in set_bit_list if bit >= 32]) > 0:
      print("Err  : reg %s addr 0x%08x bit out range !!!" % (reg['name'], reg['addr']))
      err = 1

    if len(bit_list) != len(set_bit_list):
      overlap_bit = [ bit for bit in set_bit_list if bit_list.count(bit) > 1]
      print("Err  : 0x%08x bit %s overlap !!!" % (reg['addr'], str(overlap_bit)))
      err = 1

  if err:
    sys.exit(1)
# ==========================================================
#  check overlap                                     end#}}}
# ==========================================================

# ==========================================================
#  gen io port                                     start#{{{
# ==========================================================
def gen_io_port(data):
  io_str = []
  rw_list = [ reg for reg in data if reg['type'] == 'RW']
  ro_list = [ reg for reg in data if reg['type'] == 'RO']

  # output port
  io_str.append("  // output port\n")
  for reg in rw_list:
    for bit in reg['bit']:
      bit_range = bit[1]
      bit_len   = bit_range[0] - bit_range[1]

      if bit_len != 0:
        range_str = "[%d:0]" % bit_len
      else:
        range_str = ""

      bit_name_str = "o_sw_%s" % bit[0]

      io_str.append("  ,output %-17s %s\n" % (range_str, bit_name_str,))
  io_str.append("\n");

  # input port
  io_str.append("  // input port\n")
  for reg in ro_list:
    for bit in reg['bit']:
      bit_range = bit[1]
      bit_len   = bit_range[0] - bit_range[1]

      if bit_len != 0:
        range_str = "[%d:0]" % bit_len
      else:
        range_str = ""

      bit_name_str = "i_ro_%s" % bit[0]

      io_str.append("  ,input  %-17s %s\n" % (range_str, bit_name_str,))
  io_str.append("\n");

  return io_str

# ==========================================================
#  gen io port                                       end#}}}
# ==========================================================

# ==========================================================
#  gen localparam                                  start#{{{
# ==========================================================
def gen_localparam(data):
  localparam_str = []
  for reg in data:
    addr_name = "%s_ADDR" % reg['name'].upper()
    addr_str  = "16'h%04x" % reg['addr']

    localparam_str.append("localparam %-36s = %s ;\n" % (addr_name, addr_str,))

  return localparam_str

# ==========================================================
#  gen localparam                                    end#}}}
# ==========================================================

# ==========================================================
#  gen reg wire                                    start#{{{
# ==========================================================
def gen_reg_wire(data):
  reg_wire_str = []
  rw_list = [ reg for reg in data if reg['type'] == 'RW']

  reg_wire_str.append("\n")
  # write signal
  reg_wire_str.append("http:// write signal\n")
  for reg in rw_list:
    wire_name = "wr_%s_w" % reg['name']

    reg_wire_str.append("wire        %-47s;\n" % wire_name)
  reg_wire_str.append("\n")

  # reg
  reg_wire_str.append("http:// reg\n")
  for reg in rw_list:
    reg_name = "reg_%s_r" % reg['name']

    reg_wire_str.append("reg  [31:0] %-47s;\n" % reg_name)
  reg_wire_str.append("\n")

  # read data
  reg_wire_str.append("http:// read data\n")
  for reg in data:
    wire_name = "rdata_%s_w" % reg['name']

    reg_wire_str.append("wire [31:0] %-47s;\n" % wire_name)
  reg_wire_str.append("\n")

  return reg_wire_str
# ==========================================================
#  gen reg wire                                      end#}}}
# ==========================================================

# ==========================================================
#  gen write signal                                start#{{{
# ==========================================================
def gen_write_signal(data):
  write_signal_str = []
  rw_list = [ reg for reg in data if reg['type'] == 'RW']

  for reg in rw_list:
    wire_name = "wr_%s_w" % reg['name']
    addr_name = "%s_ADDR" % reg['name'].upper()

    write_signal_str.append("assign %-20s = wr & (addr == %-14s);\n" % (wire_name, addr_name,))

  return write_signal_str
# ==========================================================
#  gen write signal                                  end#}}}
# ==========================================================

# ==========================================================
#  gen reg                                         start#{{{
# ==========================================================
def gen_reg(data):
  reg_str = []
  for reg in data:
    reg_str.append("http://==========================================================\n")
    reg_str.append("http:// %-44s start/*{{{*/\n" % reg['name'])
    reg_str.append("http://==========================================================\n")

    reg_name       = "reg_%s_r"     % reg['name']
    value_bit_name = "%s_VALID_BIT" % reg['name'].upper()
    default_name   = "%s_DEFAULT"   % reg['name'].upper()
    write_name     = "wr_%s_w"      % reg['name']
    rdata_name     = "rdata_%s_w"   % reg['name']
    if reg['type'] == 'RW':
      # localparam
      value_bit = 0
      default   = 0
      for bit in reg['bit']:
        bit_range = bit[1]
        bit_def   = bit[2]
        bit_start = bit_range[1]
        bit_end   = bit_range[0]
        bit_len   = bit_end - bit_start + 1
        value_bit |= (((2**bit_len) - 1) << bit_start)
        default   |= bit_def << bit_start

      value_bit_str = "%08x" % value_bit
      default_str   = "%08x" % default

      value_bit_str = "_".join([ value_bit_str[i*2:i*2+2] for i in range(4)])
      default_str   = "_".join([ default_str[i*2:i*2+2] for i in range(4)])

      reg_str.append("localparam %-30s = 32'h%s;\n" % (value_bit_name, value_bit_str))
      reg_str.append("localparam %-30s = 32'h%s;\n" % (default_name, default_str))
      reg_str.append("\n")

      # reg function
      reg_str.append("always@(posedge i_clk) begin\n" )
      reg_str.append("  if(i_rst_n == 1'd0) begin\n"  )
      reg_str.append("    %s <= %s;\n"                % (reg_name, default_name,))
      reg_str.append("  end\n"                        )
      reg_str.append("  else if(%s) begin\n"          % write_name)
      reg_str.append("    %s <= wdata & %s;\n"        % (reg_name, value_bit_name,))
      reg_str.append("  end\n"                        )
      reg_str.append("end\n"                          )
      reg_str.append("\n"                             )

      # output
      for bit in reg['bit']:
        output_name = "o_sw_%s" % bit[0]
        bit_range   = bit[1]
        bit_start   = bit_range[1]
        bit_end     = bit_range[0]
        bit_len     = bit_end - bit_start + 1

        if bit_len > 1:
          bit_range_str = "[%d:%d]" % (bit_end, bit_start)
        else:
          bit_range_str = "[%d]" % bit_start

        reg_str.append("assign %-16s = %s%s;\n" % (output_name, reg_name, bit_range_str,))
      reg_str.append("\n")

    # rdata
    bit_index  = 0
    rdata_list = []
    for bit in reg['bit']:
      bit_range   = bit[1]
      bit_start   = bit_range[1]
      bit_end     = bit_range[0]

      if bit_index != bit_start:
        rdata_list.append("%d'd0" % (bit_start - bit_index))
      if reg['type'] == "RW":
        rdata_list.append("o_sw_%s" % bit[0])
      else:
        rdata_list.append("i_ro_%s" % bit[0])
      bit_index = bit_end + 1
    if bit_index != 32:
      rdata_list.append("%d'd0" % (32 - bit_index))

    reg_str.append("assign %s = {\n" % rdata_name)
    reg_str.append("    " + "\n   ,".join(rdata_list[::-1]) + "\n")
    reg_str.append("};\n")

      
    reg_str.append("http://==========================================================\n")
    reg_str.append("http:// %-44s   end/*}}}*/\n" % reg['name'])
    reg_str.append("http://==========================================================\n")
    reg_str.append("\n")

  return reg_str
# ==========================================================
#  gen reg                                           end#}}}
# ==========================================================

# ==========================================================
#  gen rdata                                       start#{{{
# ==========================================================
def gen_rdata(data):
  rdata_str = []
  for reg in data:
    addr_name  = "%s_ADDR"    % reg['name'].upper()
    rdata_name = "rdata_%s_w" % reg['name']

    rdata_str.append("    %-22s : rdata <= %-21s;\n" % (addr_name, rdata_name,))
    
  return rdata_str
# ==========================================================
#  gen rdata                                         end#}}}
# ==========================================================

# ==========================================================
#  gen reg file                                    start#{{{
# ==========================================================
def gen_reg_file(
    mode_name,
    io_str,
    localparam_str,
    reg_wire_str,
    write_signal_str,
    reg_str,
    rdata_str,
    ):
  with open("../reg_file/%s_reg_cfg.v" % mode_name, "w") as f:
    f.write("module M%s_reg_cfg\n" % mode_name                              )
    f.write("(\n"                                                           )
    f.write("  // clk / rst_n\n"                                            )
    f.write("   input                    i_clk\n"                           )
    f.write("  ,input                    i_rst_n\n"                         )
    f.write("\n"                                                            )
    f.write("  // apb port\n"                                               )
    f.write("  ,input                    i_psel\n"                          )
    f.write("  ,input  [15:0]            i_paddr\n"                         )
    f.write("  ,input                    i_penable\n"                       )
    f.write("  ,input                    i_pwrite\n"                        )
    f.write("  ,input  [31:0]            i_pwdata\n"                        )
    f.write("  ,output [31:0]            o_prdata\n"                        )
    f.write("\n"                                                            )
    f.write("".join(io_str))
    f.write(");\n"                                                          )
    f.write("http://==========================================================\n")
    f.write("http:// apb bus ctrl                                 start/*{{{*/\n")
    f.write("http://==========================================================\n")
    f.write("wire                        wr                             ;\n")
    f.write("wire                        rd                             ;\n")
    f.write("wire      [15:0]            addr                           ;\n")
    f.write("wire      [31:0]            wdata                          ;\n")
    f.write("reg       [31:0]            rdata                          ;\n")
    f.write("\n"                                                            )
    f.write("assign wr       = i_psel &  i_penable &  i_pwrite          ;\n")
    f.write("assign rd       = i_psel & ~i_penable & ~i_pwrite          ;\n")
    f.write("assign addr     = i_paddr                                  ;\n")
    f.write("assign wdata    = i_pwdata                                 ;\n")
    f.write("assign o_prdata = rdata                                    ;\n")
    f.write("http://==========================================================\n")
    f.write("http:// apb bus ctrl                                   end/*}}}*/\n")
    f.write("http://==========================================================\n")
    f.write("\n"                                                            )
    f.write("http://==========================================================\n")
    f.write("http:// localparam                                   start/*{{{*/\n")
    f.write("http://==========================================================\n")
    f.write("".join(localparam_str))
    f.write("http://==========================================================\n")
    f.write("http:// localparam                                     end/*}}}*/\n")
    f.write("http://==========================================================\n")
    f.write("\n"                                                            )
    f.write("http://==========================================================\n")
    f.write("http:// reg and wire                                 start/*{{{*/\n")
    f.write("http://==========================================================\n")
    f.write("".join(reg_wire_str))
    f.write("http://==========================================================\n")
    f.write("http:// reg and wire                                   end/*}}}*/\n")
    f.write("http://==========================================================\n")
    f.write("\n"                                                            )
    f.write("http://==========================================================\n")
    f.write("http:// write signal gen                             start/*{{{*/\n")
    f.write("http://==========================================================\n")
    f.write("".join(write_signal_str))
    f.write("http://==========================================================\n")
    f.write("http:// write signal gen                               end/*}}}*/\n")
    f.write("http://==========================================================\n")
    f.write("\n"                                                            )
    f.write("".join(reg_str))
    f.write("http://==========================================================\n")
    f.write("http:// rdata                                        start/*{{{*/\n")
    f.write("http://==========================================================\n")
    f.write("always@(posedge i_clk) begin\n"                                )
    f.write("  if(i_rst_n == 1'd0) begin\n"                                 )
    f.write("    rdata <= 32'd0;\n"                                         )
    f.write("  end\n"                                                       )
    f.write("  else if(rd) begin\n"                                         )
    f.write("    case(addr)\n"                                              )
    f.write("".join(rdata_str))
    f.write("    default                : rdata <= 32'd0                ;\n")
    f.write("    endcase\n"                                                 )
    f.write("  end\n"                                                       )
    f.write("  else begin\n"                                                )
    f.write("    rdata <= rdata;\n"                                         )
    f.write("  end\n"                                                       )
    f.write("end\n"                                                         )
    f.write("http://==========================================================\n")
    f.write("http:// rdata                                          end/*}}}*/\n")
    f.write("http://==========================================================\n")
    f.write("\n"                                                            )
    f.write("endmodule\n"                                                   )

    f.close()
# ==========================================================
#  gen reg file                                      end#}}}
# ==========================================================

if __name__ == '__main__':
  if(len(sys.argv) < 2):
    print("not have input file")
    print("    %s reg_list" % sys.argv[0])
    sys.exit(0)
  file_name = sys.argv[1]

  mode_name = file_name.split("_")[0]

  data = get_reg_list(file_name)
  add_default(data)
  check_overlap(data)

  io_str           = gen_io_port(data)
  localparam_str   = gen_localparam(data)
  reg_wire_str     = gen_reg_wire(data)
  write_signal_str = gen_write_signal(data)
  reg_str          = gen_reg(data)
  rdata_str        = gen_rdata(data)

  gen_reg_file(
    mode_name,
    io_str,
    localparam_str,
    reg_wire_str,
    write_signal_str,
    reg_str,
    rdata_str,
  )

如果生成不了或是錯(cuò)誤可能是下面幾點(diǎn)
1.列表文件名不是<name>_reg_list
2.列表文件中列表名和文件不一致
3.代碼中生成目錄為 "../reg_file/<name>_reg_cfg.v"灵迫,需要有相應(yīng)的目錄才能生成
4.是不是python版本問題


如果有問題或是有想探討的可以加我微信:anyuexiu

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市晦溪,隨后出現(xiàn)的幾起案子瀑粥,更是在濱河造成了極大的恐慌,老刑警劉巖三圆,帶你破解...
    沈念sama閱讀 211,561評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件狞换,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡嫌术,警方通過查閱死者的電腦和手機(jī)哀澈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來度气,“玉大人割按,你說我怎么就攤上這事×准” “怎么了适荣?”我有些...
    開封第一講書人閱讀 157,162評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵现柠,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我弛矛,道長(zhǎng)够吩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,470評(píng)論 1 283
  • 正文 為了忘掉前任丈氓,我火速辦了婚禮周循,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘万俗。我一直安慰自己湾笛,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,550評(píng)論 6 385
  • 文/花漫 我一把揭開白布闰歪。 她就那樣靜靜地躺著嚎研,像睡著了一般。 火紅的嫁衣襯著肌膚如雪库倘。 梳的紋絲不亂的頭發(fā)上临扮,一...
    開封第一講書人閱讀 49,806評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音教翩,去河邊找鬼杆勇。 笑死,一個(gè)胖子當(dāng)著我的面吹牛迂曲,可吹牛的內(nèi)容都是我干的靶橱。 我是一名探鬼主播,決...
    沈念sama閱讀 38,951評(píng)論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼路捧,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼关霸!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起杰扫,我...
    開封第一講書人閱讀 37,712評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤队寇,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后章姓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體佳遣,經(jīng)...
    沈念sama閱讀 44,166評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,510評(píng)論 2 327
  • 正文 我和宋清朗相戀三年凡伊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了零渐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,643評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡系忙,死狀恐怖诵盼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤风宁,帶...
    沈念sama閱讀 34,306評(píng)論 4 330
  • 正文 年R本政府宣布洁墙,位于F島的核電站,受9級(jí)特大地震影響戒财,放射性物質(zhì)發(fā)生泄漏热监。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,930評(píng)論 3 313
  • 文/蒙蒙 一饮寞、第九天 我趴在偏房一處隱蔽的房頂上張望孝扛。 院中可真熱鬧,春花似錦幽崩、人聲如沸疗琉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至凑耻,卻和暖如春太示,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背香浩。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工类缤, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人邻吭。 一個(gè)月前我還...
    沈念sama閱讀 46,351評(píng)論 2 360
  • 正文 我出身青樓餐弱,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親囱晴。 傳聞我的和親對(duì)象是個(gè)殘疾皇子膏蚓,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,509評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 組件 計(jì)算機(jī)是一種數(shù)據(jù)處理設(shè)備,它由CPU和內(nèi)存以及外部設(shè)備組成畸写。CPU負(fù)責(zé)數(shù)據(jù)處理驮瞧,內(nèi)存負(fù)責(zé)存儲(chǔ),外部設(shè)備負(fù)責(zé)數(shù)...
    哆啦灬少A夢(mèng)閱讀 1,576評(píng)論 1 2
  • 一枯芬、Python簡(jiǎn)介和環(huán)境搭建以及pip的安裝 4課時(shí)實(shí)驗(yàn)課主要內(nèi)容 【Python簡(jiǎn)介】: Python 是一個(gè)...
    _小老虎_閱讀 5,725評(píng)論 0 10
  • 一论笔、溫故而知新 1. 內(nèi)存不夠怎么辦 內(nèi)存簡(jiǎn)單分配策略的問題地址空間不隔離內(nèi)存使用效率低程序運(yùn)行的地址不確定 關(guān)于...
    SeanCST閱讀 7,784評(píng)論 0 27
  • feisky云計(jì)算、虛擬化與Linux技術(shù)筆記posts - 1014, comments - 298, trac...
    不排版閱讀 3,827評(píng)論 0 5
  • 一個(gè)計(jì)數(shù)器通常是由一組觸發(fā)器構(gòu)成千所,該組觸發(fā)器按照預(yù)先給定的順序改變其狀態(tài)狂魔,如果所有觸發(fā)器的狀態(tài)改變是在同一時(shí)鐘脈沖...
    錦穗閱讀 13,262評(píng)論 0 6