u@home:~$

加个新的自定义寄存器,其中的一个bit被设置为1后就无法再改回去

目的就是做这么一个bit,相当于一个开关吧。系统reset的时候是0,一但被设置成1,就一直是1了,没法再改回去了。

比如记得smram系统初始化时是可以写的,然后就被写保护了。

用这个bit是不是可以做类似的功能?

代码很简单,新加个csr.bsec寄存器,选个0x100,好记,好像loongarch手册上没用这段,但也没说这部分是不是能自定义。

bit 0叫ef,eeprom flush。表示这个bit设置后,eeprom就不能再刷了。

看了下一般eeprom的接口都是i2c,然后还有一个写保护的pin。

/////
//
//  All the exceptions are handled at _e stage, including ale, illinstr, badaddr
//
//  For example, illegal instruction exception happens at _d stage. Handle different types of exception
//  at different stages make things more complicated. Should choose between pc_d and pc_e to store.
//  And exception happened at _e has a higher priority, becasue it is from the elderly instruction.
//   
//
module cpu7_csr(
   input                                clk,
   input                                resetn,
   output [`GRLEN-1:0]                  csr_rdata,
   input  [`LSOC1K_CSR_BIT-1:0]         csr_raddr,
   input  [`GRLEN-1:0]                  csr_wdata,
   input  [`LSOC1K_CSR_BIT-1:0]         csr_waddr,
   input                                csr_wen,

   output [`GRLEN-1:0]                  csr_eentry,
   output [`GRLEN-1:0]                  csr_era,
   input                                ecl_csr_ale_e,
   input                                ecl_csr_illinst_e,
   input  [`GRLEN-1:0]                  ifu_exu_pc_e,
   input                                ecl_csr_ertn_e
   );


   wire exception;
   assign exception = ecl_csr_ale_e | ecl_csr_illinst_e; // | other exception

   //
   //  CRMD
   //
   
   wire [`GRLEN-1:0]       crmd;
   wire                    crmd_wen;
   assign crmd_wen = (csr_waddr == `LSOC1K_CSR_CRMD) && csr_wen;

   
   wire                    crmd_ie;
   wire                    crmd_ie_wdata;
   wire                    crmd_ie_nxt;

   assign crmd_ie_wdata = csr_wdata[`CRMD_IE];

//   dp_mux2es #(1) crmd_ie_mux(
//      .dout (crmd_ie_nxt),
//      .in0  (crmd_ie_wdata),
//      .in1  (1'b0),
//      .sel  (exception));

   wire crmd_ie_mux_sel_wdata_l;
   wire crmd_ie_mux_sel_zero_l;
   wire crmd_ie_mux_sel_prmdpie_l;
   
   assign crmd_ie_mux_sel_wdata_l = ~crmd_wen;
   assign crmd_ie_mux_sel_zero_l = ~exception;
   assign crmd_ie_mux_sel_prmdpie_l = ~ecl_csr_ertn_e;
   
   dp_mux3ds #(1) crmd_ie_mux(
      .dout   (crmd_ie_nxt),
      .in0    (crmd_ie_wdata),
      .in1    (1'b0),
      .in2    (prmd_pie),
      .sel0_l (crmd_ie_mux_sel_wdata_l),
      .sel1_l (crmd_ie_mux_sel_zero_l),
      .sel2_l (crmd_ie_mux_sel_prmdpie_l));
         
   dffe_s #(1) crmd_ie_reg (
      .din (crmd_ie_nxt),
      .en  (crmd_wen | exception | ecl_csr_ertn_e),
      .clk (clk),
      .q   (crmd_ie),
      .se(), .si(), .so());
   
   
   wire [1:0]             crmd_plv;
   wire [1:0]             crmd_plv_wdata;
   wire [1:0]             crmd_plv_nxt;

   assign crmd_plv_wdata = csr_wdata[`CRMD_PLV];

//   dp_mux2es #(2) crmd_plv_mux(
//      .dout (crmd_plv_nxt),
//      .in0  (crmd_plv_wdata),
//      .in1  (2'b0),
//      .sel  (exception));

   wire crmd_plv_mux_sel_wdata_l;
   wire crmd_plv_mux_sel_zero_l;
   wire crmd_plv_mux_sel_prmdpplv_l;

   assign crmd_plv_mux_sel_wdata_l = ~crmd_wen;
   assign crmd_plv_mux_sel_zero_l = ~exception;
   assign crmd_plv_mux_sel_prmdpplv_l = ~ecl_csr_ertn_e;
  
   dp_mux3ds #(2) crmd_plv_mux(
      .dout   (crmd_plv_nxt),
      .in0    (crmd_plv_wdata),
      .in1    (2'b0),
      .in2    (prmd_pplv),
      .sel0_l (crmd_plv_mux_sel_wdata_l),
      .sel1_l (crmd_plv_mux_sel_zero_l),
      .sel2_l (crmd_plv_mux_sel_prmdpplv_l));
   
   dffe_s #(2) crmd_plv_reg (
      .din (crmd_plv_nxt),
      .en  (crmd_wen | exception | ecl_csr_ertn_e),
      .clk (clk),
      .q   (crmd_plv),
      .se(), .si(), .so());

   
   assign crmd = {
		 29'b0,
		 crmd_ie,
		 crmd_plv
		 };


   //
   //  PRMD
   //

   wire [`GRLEN-1:0]      prmd;
   wire                   prmd_wen;
   assign prmd_wen = (csr_waddr == `LSOC1K_CSR_PRMD) && csr_wen;

   wire                   prmd_pie;
   wire                   prmd_pie_wdata;
   wire                   prmd_pie_nxt;
   assign prmd_pie_wdata = csr_wdata[`LSOC1K_PRMD_PIE];

   dp_mux2es #(1) prmd_pie_mux(
      .dout (prmd_pie_nxt),
      .in0  (prmd_pie_wdata),
      .in1  (crmd_ie),
      .sel  (exception));
   
   dffe_s #(1) prmd_pie_reg (
      .din (prmd_pie_nxt),
      .en  (prmd_wen | exception),
      .clk (clk),
      .q   (prmd_pie),
      .se(), .si(), .so());


   wire [1:0]             prmd_pplv;
   wire [1:0]             prmd_pplv_wdata;
   wire [1:0]             prmd_pplv_nxt;
   assign prmd_pplv_wdata = csr_wdata[`LSOC1K_PRMD_PPLV];

   dp_mux2es #(2) prmd_pplv_mux(
      .dout (prmd_pplv_nxt),
      .in0  (prmd_pplv_wdata),
      .in1  (crmd_plv),
      .sel  (exception));

   dffe_s #(2) prmd_pplv_reg (
      .din (prmd_pplv_nxt),
      .en  (prmd_wen | exception),
      .clk (clk),
      .q   (prmd_pplv),
      .se(), .si(), .so());
   

   assign prmd = {
		 29'b0,
                 prmd_pie,
                 prmd_pplv
		 };

   
   //
   //  ERA 0x6
   //

   wire [`GRLEN-1:0]       era;
   wire [`GRLEN-1:0]       era_wdata;
   wire [`GRLEN-1:0]       era_nxt;
   wire                    era_wen;

   assign era_wen = (csr_waddr == `LSOC1K_CSR_EPC) && csr_wen;  // EPC is ERA

   assign era_wdata = csr_wdata;

   dp_mux2es #(`GRLEN) era_mux(
      .dout (era_nxt),
      .in0  (era_wdata),
      .in1  (ifu_exu_pc_e),
      .sel  (exception));

   dffe_s #(`GRLEN) era_reg (
      .din (era_nxt),
      .en  (era_wen | exception),
      .clk (clk),
      .q   (era),
      .se(), .si(), .so());
   
   assign csr_era = era;

   //
   //  EENTRY 0xc
   //

   wire [`GRLEN-1:0]       eentry;
   wire [`GRLEN-1:0]       eentry_nxt;
   wire                    eentry_wen;

   assign eentry_nxt = csr_wdata;
   assign eentry_wen = (csr_waddr == `LSOC1K_CSR_EBASE) && csr_wen; // EBASE is EENTRY

   dffe_s #(`GRLEN) eentry_reg (
      .din (eentry_nxt),
      .en  (eentry_wen),
      .clk (clk),
      .q   (eentry),
      .se(), .si(), .so());

   assign csr_eentry = eentry;


   

   //
   //  SELF DEFINED: BSEC (BOOT SECURITY) 0x100
   //

   wire [`GRLEN-1:0]       bsec;
   wire [`GRLEN-1:0]       bsec_nxt;
   wire                    bsec_wen;

   assign bsec_wen = (csr_waddr == `LSOC1K_CSR_BSEC) && csr_wen;

   // bit 0, eeprom flush
   wire                    bsec_ef;
   wire                    bsec_ef_wdata;
   wire                    bsec_ef_nxt;

   assign bsec_ef_wdata = csr_wdata[`LSOC1K_BSEC_EF];
   assign bsec_ef_nxt = bsec_ef_wdata | bsec_ef;
   
   dffre_s #(1) bsec_ef_reg (
      .din (bsec_ef_nxt),
      .en  (bsec_wen),
      .clk (clk),
      .rst (~resetn),
      .q   (bsec_ef),
      .se(), .si(), .so());

   
   assign bsec = {
		 31'b0,
                 bsec_ef
		 };


   


   
   
   assign csr_rdata = {`GRLEN{csr_raddr == `LSOC1K_CSR_CRMD}}  & crmd   |
		      {`GRLEN{csr_raddr == `LSOC1K_CSR_PRMD}}  & prmd   |
		      {`GRLEN{csr_raddr == `LSOC1K_CSR_EPC}}   & era    |
		      {`GRLEN{csr_raddr == `LSOC1K_CSR_EBASE}} & eentry |
		      {`GRLEN{csr_raddr == `LSOC1K_CSR_BSEC}}  & bsec   |
		      `GRLEN'b0;

endmodule // cpu7_csr

和普通的寄存器没太大区别,用了带reset的dff。还没有机会能学到什么时候可以用reset的dff,什么样的寄存器可以reset。 因为我觉得reset这个信号fanout肯定也大,异步reset,但可能需要同步完成,不知道有没有reset tree。

逻辑上就多了这一句。

   assign bsec_ef_nxt = bsec_ef_wdata | bsec_ef;

测试代码:

.text
        .globl  _start
        .globl  start
        .globl  __main
_start:
start:
    csrrd      $r3, 0x100         # bsec, should be all zero after reset
    bne        $r3, $r0, error

    addi.w     $r3, $r0, -0x1     # r3 = ffffffff
    csrwr      $r3, 0x100         # set bsec.ef to 1
    csrrd      $r6, 0x100         # r6 should read 0x1
    addi.w     $r4, $r0, 0x1
    bne        $r6, $r4, error

# once bsec.ef is set to 1, it can not be reset to 0
    csrwr      $r0, 0x100         # try to clear bsec
    csrrd      $r6, 0x100         # r6 should read 0x1
    bne        $r6, $r4, error

# try again
    csrwr      $r0, 0x100         # try to clear bsec
    csrrd      $r6, 0x100         # r6 should read 0x1
    bne        $r6, $r4, error

success:
    addi.w     $r5, $r0, 0x3a     # r5 = 0x3a
error:
    addi.w     $r5, $r5, 0x20     # r5 = 0x5a if go through success, otherwise 0x20

loop:
    beq        $r0, $r0, loop