add core
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Wed, 25 Jul 2018 03:29:58 +0000 (04:29 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Wed, 25 Jul 2018 03:29:58 +0000 (04:29 +0100)
40 files changed:
src/core/PTWalk.bsv [new file with mode: 0644]
src/core/alu.bsv [new file with mode: 0644]
src/core/branchpredictor.bsv [new file with mode: 0644]
src/core/core.bsv [new file with mode: 0644]
src/core/csr.bsv [new file with mode: 0644]
src/core/dTLB.bsv [new file with mode: 0755]
src/core/dcache_asic.bsv [new file with mode: 0644]
src/core/dcache_asic_generic.bsv [new file with mode: 0644]
src/core/decode.defines [new file with mode: 0644]
src/core/decode_opfetch.bsv [new file with mode: 0644]
src/core/decoder.bsv [new file with mode: 0644]
src/core/defined_parameters.bsv [new file with mode: 0644]
src/core/defined_types.bsv [new file with mode: 0644]
src/core/dmem.bsv [new file with mode: 0644]
src/core/execute_stage.bsv [new file with mode: 0644]
src/core/fetch_stage.bsv [new file with mode: 0644]
src/core/fpu/fpu.bsv [new file with mode: 0644]
src/core/fpu/fpu_compare_min_max.bsv [new file with mode: 0644]
src/core/fpu/fpu_convert_sp_dp.bsv [new file with mode: 0644]
src/core/fpu/fpu_divider.bsv [new file with mode: 0644]
src/core/fpu/fpu_dp_to_int.bsv [new file with mode: 0644]
src/core/fpu/fpu_fclass.bsv [new file with mode: 0755]
src/core/fpu/fpu_fm_add_sub.bsv [new file with mode: 0644]
src/core/fpu/fpu_int_to_dp.bsv [new file with mode: 0644]
src/core/fpu/fpu_int_to_sp.bsv [new file with mode: 0644]
src/core/fpu/fpu_sign_injection.bsv [new file with mode: 0644]
src/core/fpu/fpu_sp_to_int.bsv [new file with mode: 0644]
src/core/fpu/fpu_sqrt.bsv [new file with mode: 0644]
src/core/fpu/integer_divider.bsv [new file with mode: 0644]
src/core/fpu/integermultiplier.bsv [new file with mode: 0644]
src/core/iTLB.bsv [new file with mode: 0644]
src/core/icache.bsv [new file with mode: 0644]
src/core/icache_asic.bsv [new file with mode: 0644]
src/core/imem.bsv [new file with mode: 0644]
src/core/mem_config1.bsv [new file with mode: 0644]
src/core/memory_stage.bsv [new file with mode: 0644]
src/core/muldiv.bsv [new file with mode: 0644]
src/core/prf.bsv [new file with mode: 0644]
src/core/registerfile.bsv [new file with mode: 0644]
src/core/riscv.bsv [new file with mode: 0644]

diff --git a/src/core/PTWalk.bsv b/src/core/PTWalk.bsv
new file mode 100644 (file)
index 0000000..7e7ff67
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+Copyright (c) 2013, IIT Madras
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+*  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+*  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+*  Neither the name of IIT Madras  nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+*/
+package PTWalk;
+
+import ConfigReg:: *;
+import defined_types::*;
+import GetPut::*;
+
+
+       function TLB_permissions ptw_to_tlb_perms(Bit#(10) perms);
+               return TLB_permissions { v : perms[0],
+                                                                                                                r : perms[1],
+                                                                                                                w : perms[2],
+                                                                                                                x : perms[3],
+                                                                                                                u : perms[4],
+                                                                                                                g : perms[5],
+                                                                                                                a : perms[6],
+                                                                                                                d : perms[7]};
+       endfunction
+       
+       //interface Ifc_TLB#(numeric type vaddr, numeric type page_size, numeric type paddr, numeric type asid_width);
+       //      method Action get_vpn(Request_PPN_PTW#(vaddr,page_size) req);
+       //      method ActionValue#(Response_PPN_TLB#(paddr, page_size, asid_width)) send_ppn;
+       //endinterface
+
+       interface Ifc_memory#(numeric type data_width);
+               method ActionValue#(Request_PTE_memory#(data_width)) send_PTE_pointer;
+               method Action get_PTE(Bit#(data_width) pte);
+       endinterface
+
+       interface Ifc_PTWalk#(numeric type data_width, 
+                                                                                               numeric type vaddr, 
+                                                                                               numeric type paddr, 
+                                                                                               numeric type real_paddr, 
+                                                                                               numeric type asid_width,
+                                                                                               numeric type page_size);
+               interface Put#(Request_PPN_PTW#(vaddr,page_size)) frm_TLB;
+               interface Get#(Tuple2#(Bool,To_TLB#(real_paddr,page_size,asid_width))) to_TLB;
+               interface Ifc_memory#(data_width) ifc_memory;
+               method Action satp_frm_csr(Bit#(data_width) satp);
+               method Action flush(Translation_type _flush);
+               //method Bool ptwalkdone;
+               //method Maybe#(Translation_type) page_fault;
+       endinterface
+
+       module mkPTWalk(Ifc_PTWalk#(data_width,vaddr_width,paddr_width, real_paddr, asid_width,page_size_bits))
+               provisos(
+                       Mul#(8,no_of_bytes, data_width),
+                       Log#(no_of_bytes, addressable_bits),
+                       Log#(data_width, data_width_bits),
+                       Add#(vpn_width, page_size_bits, vaddr_width),
+                       Add#(vpn_split, addressable_bits, page_size_bits),
+                       Add#(ppn_width, page_size_bits, paddr_width),
+                       Add#(real_ppn_width, page_size_bits, real_paddr),
+                       Mul#(vpn_split, levels, vpn_width),
+                       Add#(10, ppn_width, ppn_perm),
+                       Add#(y_, ppn_width, data_width),
+                       Add#(x_, real_ppn_width, data_width),
+                       Add#(a_, ppn_perm, data_width),
+                       Add#(b_, paddr_width, data_width),
+                       Add#(c_, 10, data_width),
+                       Add#(d_, vpn_width, data_width),
+                       Add#(1, sub_levels, levels)
+                       );
+
+               let v_data_width = valueOf(data_width);
+               let v_data_width_bits = valueOf(data_width_bits);
+               let v_vpn_width = valueOf(vpn_width);
+               let v_vpn_split = valueOf(vpn_split);
+               let v_ppn_width = valueOf(ppn_width);
+               let v_real_ppn_width = valueOf(real_ppn_width);
+               let v_asid_width = valueOf(asid_width);
+               let v_levels = valueOf(levels);
+               let v_sub_levels = valueOf(sub_levels);
+               let v_addressable_bits = valueOf(addressable_bits);
+
+               function Tuple2#(Bool, Bit#(ppn_perm)) fn_super_page_physical_address(Bit#(vpn_width) vpn,
+                                                                                                                                                                                                                                                                                                        Bit#(data_width) pte,
+                                                                                                                                                                                                                                                                                                        Int#(32) levels);
+                               Bool page_fault = !unpack(pte[0]);
+                               Bit#(ppn_width) step_ppn = 0;
+                               if(levels==3) begin
+                                       Bit#(TMul#(3,vpn_split)) offset_3 = pte[3*v_vpn_split+9:10];
+                                       Bit#(TSub#(ppn_width,TMul#(3,vpn_split))) ppn= pte[v_ppn_width+9:3*v_vpn_split+10];
+                                       Bit#(TMul#(3,vpn_split)) vpn_offset = vpn[3*v_vpn_split-1:0];
+                                       step_ppn = {ppn,vpn_offset};
+                                       if(offset_3!=0)
+                                               page_fault = True;
+                               end
+                               else if(levels==2) begin
+                                       Bit#(TMul#(2,vpn_split)) offset_2 = pte[2*v_vpn_split+9:10];
+                                       Bit#(TSub#(ppn_width,TMul#(2,vpn_split))) ppn= pte[v_ppn_width+9:2*v_vpn_split+10];
+                                       Bit#(TMul#(2,vpn_split)) vpn_offset = vpn[2*v_vpn_split-1:0];
+                                       step_ppn = {ppn,vpn_offset};
+                                       if(offset_2!=0)
+                                               page_fault = True;
+                               end
+                               else if(levels==1) begin
+                                       Bit#(TMul#(1,vpn_split)) offset_1 = pte[1*v_vpn_split+9:10];
+                                       Bit#(TSub#(ppn_width,TMul#(1,vpn_split))) ppn= pte[v_ppn_width+9:1*v_vpn_split+10];
+                                       Bit#(TMul#(1,vpn_split)) vpn_offset = vpn[1*v_vpn_split-1:0];
+                                       step_ppn = {ppn,vpn_offset};
+                                       if(offset_1!=0)
+                                               page_fault = True;
+                               end
+                       return tuple2(page_fault,{step_ppn,pte[9:0]});
+               endfunction
+                                                        
+               Reg#(Bit#(vpn_width)) rg_vpn <- mkReg(0);
+               Reg#(Int#(32))  rg_levels <- mkConfigReg(fromInteger(v_sub_levels));
+               Reg#(Bit#(data_width)) rg_ppn[2] <- mkCReg(2,0);
+               Reg#(Bit#(asid_width)) rg_asid[2] <- mkCReg(2,0);
+               Reg#(Bit#(data_width)) rg_pte <- mkReg(0);
+               Reg#(Bit#(data_width)) rg_pte_pointer <- mkReg(0);
+               Reg#(PTW_state) rg_ptw_state[2] <- mkCReg(2,PTW_ready);
+               Reg#(Bit#(data_width)) rg_satp <- mkReg(0);
+               Reg#(Bool) rg_page_fault <- mkReg(False);
+               Reg#(Bit#(10)) rg_permission_bits <- mkReg(0);
+               Reg#(Translation_type) rg_page_type <- mkConfigReg(Load);
+               Wire#(Bool) wr_flush <- mkDWire(False);
+               
+               //(*conflict_free="rl_computer_next_pointer, rl_return_from_page_fault"*)
+               rule rl_computer_next_pointer(rg_ptw_state[1] == Handling_PTW && !wr_flush);
+                               Int#(32) vpn_trnct = (rg_levels+1)*fromInteger(v_vpn_split);
+                               Bit#(vpn_split) lv_vpn_split = rg_vpn[vpn_trnct-1:vpn_trnct-fromInteger(v_vpn_split)];
+                               Bit#(page_size_bits) vpn_addr = zeroExtend(lv_vpn_split);
+                               vpn_addr = vpn_addr << v_addressable_bits;
+                               `ifdef verbose $display($time, "\tPTW: The VPN split bits are  %d split is %h", vpn_trnct, vpn_addr); `endif
+                               Int#(32) ppn_trnct = (rg_levels)*fromInteger(v_vpn_split) + 10;
+                               Bit#(ppn_width) p_pte= rg_pte[v_ppn_width+9:10];
+                               Bit#(data_width) lv_zeros = 0;
+                               rg_permission_bits <= rg_pte[9:0];
+                               `ifdef verbose $display($time, "\tPTW: page table entry %h and page level is %d", rg_pte, rg_levels); `endif
+                               if(rg_pte[0]==0 || (rg_pte[1]==0 && rg_pte[2]==1)) begin
+                                       rg_ptw_state[1] <= PTW_done;
+                                       `ifdef verbose  $display($time,"\tPTW: Page Fault due to reason1 "); `endif
+                                       rg_page_fault <= True;
+                               end
+                               else if((rg_pte[3]==1 || rg_pte[1]==1)) begin //if executable and read permission bits are 1 then it is a super page
+                                       rg_ptw_state[1] <= PTW_done;
+                                       match{.x,.y} = fn_super_page_physical_address(rg_vpn,rg_pte,rg_levels+1);
+                                       if(x) begin
+                                               rg_page_fault <= True;
+                                               `ifdef verbose  $display($time,"Page Fault due to reason2 "); `endif
+                                       end
+                                       else begin
+                                               rg_pte <= zeroExtend(y);
+                                               `ifdef verbose  $display($time,"Superpage has been found"); `endif
+                                               if(rg_pte[6]==0 || (rg_page_type==Store && rg_pte[7]==0))
+                                                       rg_page_fault <= True;
+                                       end
+                                       //if(rg_pte[ppn_trnct-1:10]!=0) begin TODO
+                                               //Bit#(data_width) pte_paddr = rg_pte << ppn_trnct;
+                                               //Bit#(vpn_width) pte_vpn = rg_vpn << rg_levels*(fromInteger(v_vpn_split));
+                                               //Bit#(data_width) pte_vaddr = zeroExtend(pte_vpn);
+                                               //pte_vaddr = pte_vaddr >> rg_levels*fromInteger(v_vpn_split);
+                                               //rg_pte_pointer <= pte_paddr | pte_vaddr;
+                                               //`ifdef verbose $display($time, "\t It's is a superpage %h", pte_paddr | pte_vaddr); `endif
+                                       //end
+                                       //else
+                                       //      rg_page_fault <= True;
+                               end
+                               else begin/* if(rg_levels == 0) begin
+                                       rg_ptw_state[1] <= Wait_for_memory;
+                                       rg_pte_pointer <= {rg_pte[v_data_width-1:10],lv_zeros[9:0]};
+                                       `ifdef verbose 
+                                       Bit#(data_width) pte_pointer = {rg_pte[v_data_width-1:10],lv_zeros[9:0]};
+                                       $display($time, "\t  %h", pte_pointer); `endif
+                               end
+                               else if(rg_levels != 0) begin*/
+                                       Bit#(paddr_width) lv_pte_pointer = {p_pte,vpn_addr}; 
+                                       rg_pte_pointer <= zeroExtend(lv_pte_pointer);
+                                       rg_ptw_state[1] <= Send_to_memory;
+                                       `ifdef verbose $display($time, "\t next page table pointer %h", lv_pte_pointer); `endif
+                               end
+                                               
+               endrule 
+
+               rule rl_return_from_page_fault(wr_flush);
+                       `ifdef verbose $display($time, "\tPTW: Flushed page table walk"); `endif
+                       rg_ptw_state[1] <= PTW_ready;
+                       rg_page_fault <= False;
+                       rg_levels <= fromInteger(v_sub_levels);
+               endrule
+
+               interface frm_TLB = interface Put
+                                                                                                       method Action put(Request_PPN_PTW#(vaddr_width,page_size_bits) req) if(rg_ptw_state[1]==PTW_ready && !wr_flush);
+                                                                                                               rg_vpn <= req.vpn;      
+                                                                                                               rg_page_type <= req.page_type;
+                                                                                                               `ifdef verbose $display($time, "\tPTW: vpn obtained is %h", req.vpn);  `endif
+                                                                                                               rg_ptw_state[1] <= Handling_PTW;
+                                                                                                       endmethod
+                                                                                               endinterface;
+
+               interface to_TLB = interface Get
+                                                                                                       method ActionValue#(Tuple2#(Bool,To_TLB#(real_paddr, page_size_bits, asid_width))) get if(rg_ptw_state[1]==PTW_done && !wr_flush);
+                                                                                                               rg_page_fault <= False;
+                                                                                                               rg_ptw_state[1] <= PTW_ready;
+                                                                                                               Bit#(2) pg_levels = truncate(pack(rg_levels) + 1);
+                                                                                                               rg_levels <= fromInteger(v_sub_levels);
+                                                                                                               if(rg_levels==fromInteger(v_sub_levels))
+                                                                                                                       pg_levels=0;
+                                                                                                               `ifdef verbose $display($time, "\tPTW: physical page number %h with permission bits  %b", rg_pte, rg_page_fault);  `endif
+                                                                                                               return tuple2(rg_page_fault, To_TLB { ppn : rg_pte[v_real_ppn_width+9:10],
+                                                                                                                                                                                                                 tlb_perm : ptw_to_tlb_perms(rg_pte[9:0]),     
+                                                                                                                                                                                                                 asid : rg_asid[1],
+                                                                                                                                                                                                                 levels : pg_levels});
+                                                                                                       endmethod
+                                                                                               endinterface;
+
+               interface ifc_memory = interface Ifc_memory
+                                                                                                       method ActionValue#(Request_PTE_memory#(data_width)) send_PTE_pointer if(!wr_flush && rg_ptw_state[1]== Send_to_memory);
+                                                                                                               `ifdef verbose $display($time, "\tPTW: Sending from PTW to dcache for address %h", rg_pte_pointer); `endif
+                                                                                                                       rg_ptw_state[1] <= Wait_for_memory;
+                                                                                                                       return Request_PTE_memory{ptwdone : (rg_ptw_state[1]==PTW_done), address : rg_pte_pointer, page_type : rg_page_type};
+                                                                                                               endmethod
+                                                                                                               method Action get_PTE(Bit#(data_width) pte) if(rg_ptw_state[1]== Wait_for_memory && !wr_flush);
+                                                                                                               `ifdef verbose $display($time, "\tPTW: pte obtained from memory %h", pte); `endif
+                                                                                                                       rg_pte <= pte;
+                                                                                                                       if(rg_levels == 0) begin        
+                                                                                                                               `ifdef verbose $display($time, "\tPTW: Last level PTW with pte %h and page fault", pte, rg_page_fault); `endif
+                                                                                                                               rg_ptw_state[1] <= PTW_done;
+                                                                                                                               if(pte[0]==0 || pte[6]==0 || (rg_page_type==Store && pte[7]==0)) begin
+                                                                                                                                       `ifdef verbose $display($time, "\tPTW: Access and dirty page fault %h", pte); `endif
+                                                                                                                                       rg_page_fault <= True;
+                                                                                                                               end
+                                                                                                                               rg_levels <= fromInteger(v_sub_levels);
+                                                                                                                       end
+                                                                                                                       else begin
+                                                                                                                               rg_ptw_state[1] <= Handling_PTW;
+                                                                                                                               rg_levels <= rg_levels-1;
+                                                                                                                       end
+                                                                                                               endmethod
+                                                                                                        endinterface;
+
+               method Action satp_frm_csr(Bit#(data_width) satp) if(rg_ptw_state[1] == PTW_ready);
+                       Bit#(ppn_width) p_pte = satp[v_ppn_width-1:0];
+                       //Bit#(data_width) pte = zeroExtend(p_pte);
+                       Bit#(10) perm_bits = 'b1;
+                       Bit#(ppn_perm) pte ={p_pte,perm_bits}; 
+                       rg_pte <= zeroExtend(pte);
+                       //`ifdef verbose $display($time, "\t page table pointer %h", p_pte); `endif
+                       rg_asid[0] <= satp[v_asid_width+v_ppn_width-1:v_ppn_width];
+               endmethod
+
+               method Action flush(Translation_type _flush);
+                       if((rg_page_type==Execution && _flush==Execution) || (rg_page_type!=Execution && _flush!=Execution))
+                         wr_flush <= True;
+               endmethod
+
+               //method Bool ptwalkdone;
+               //      Bool done = False; 
+               //      if(rg_ptw_state[1]==PTW_done)
+               //              done = True;
+               //      return done;
+               //endmethod
+
+               //method Maybe#(Translation_type) page_fault /*if(rg_ptw_state[1]==PTW_done)*/;
+               //      if(rg_page_fault)
+               //              return tagged Valid rg_page_type;
+               //      else 
+               //              return tagged Invalid;
+               //endmethod
+
+       endmodule
+endpackage
diff --git a/src/core/alu.bsv b/src/core/alu.bsv
new file mode 100644 (file)
index 0000000..ba56e46
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+Copyright (c) 2013, IIT Madras
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+*  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+*  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+*  Neither the name of IIT Madras  nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+Module name: Riscv_arithmetic_unit.
+author name: Neel Gala
+Email id:    neelgala@gmail.com
+
+This module is the arithmetic execution unit for the RISCV ISA. It is a 64 bit implementation which is named as RV64.
+The instruction with a "W" are RV64 instructions which ignore the upper 32 bits and operate on the lower 32 bits.
+The arithmetic unit is implemented as a single case statement where the instruction bits define the various operations to be executed.
+
+This module contains single cycle MUL instruction execution.
+
+*/
+
+package alu;
+
+import defined_types::*;
+`include "defined_parameters.bsv"
+`include "decode.defines"
+       (*noinline*)
+       function Tuple7#(Execution_output, Bit#(`VADDR), Flush_type, Maybe#(Training_data#(`VADDR)),Maybe#(Bit#(`VADDR)), Trap_type, Bit#(`PERFMONITORS)) fn_alu(Bit#(4) fn, Bit#(64) op1, Bit#(64) op2, Bit#(64) immediate_value, Bit#(`VADDR) pc , 
+                                                                                                                                                                                                                               Instruction_type inst_type, Bit#(`VADDR) npc, Bit#(3) funct3, Access_type mem_access, Bit#(5) rd, Bit#(2) prediction,
+                                                                                                                                                                                                                               Bit#(`PERFMONITORS) perfmonitors
+                                                                                                                                                                                                                                       `ifdef RV64 ,Bool word32 `endif );
+// TODO: use the pc of the previous stage for next-pc. This will save space in the FIFOs                                                                                                                                                                                                                                       
+// But what if the instruction in the previous stage has not yet been enqueued (in cases of page/cache misses)
+// In this case you will have to wait untill that instruction arrives before progressing. NEED TO THINK THIS THROUGH
+               /*========= Perform all the arithmetic ===== */
+               // ADD* ADDI* SUB* 
+               let inv_op2=(fn[3]==1)?~op2:op2;
+               let op1_xor_op2=op1^inv_op2;
+               let adder_output=op1+inv_op2+zeroExtend(fn[3]);
+               // SLT SLTU
+               Bit#(1) compare_out=fn[0]^(
+                                                       (fn[3]==0)?pack(op1_xor_op2==0):
+                                                       (op1[64-1]==op2[64-1])?adder_output[64-1]:
+                                                       (fn[1]==1)?op2[64-1]:op1[64-1]);
+               // SLL SRL SRA
+               Bit#(6) shift_amt={((!word32)?op2[5]:0),op2[4:0]};
+               Bit#(32) upper_bits=word32?signExtend(fn[3]&op1[31]):op1[63:32];
+               Bit#(64) shift_inright={upper_bits,op1[31:0]};
+               let shin = (fn==`FNSR || fn==`FNSRA)?shift_inright:reverseBits(shift_inright);
+               Int#(TAdd#(64,1)) t=unpack({(fn[3]&shin[64-1]),shin});
+               Int#(64) shift_r=unpack(pack(t>>shift_amt)[64-1:0]);
+               let shift_l=reverseBits(pack(shift_r));
+               Bit#(64) shift_output=((fn==`FNSR || fn==`FNSRA)?pack(shift_r):0) |
+                                                                                               ((fn==`FNSL)?                             pack(shift_l):0); 
+               // AND OR XOR
+               let logic_output=       ((fn==`FNXOR || fn==`FNOR)?op1_xor_op2:0) |
+                                                               ((fn==`FNOR || fn==`FNAND)?op1&op2:0);
+               let shift_logic=zeroExtend(pack(fn==`FNSEQ || fn==`FNSNE || fn >= `FNSLT)&compare_out) |
+                                                        logic_output|shift_output;
+               Bit#(64) final_output = (fn==`FNADD || fn==`FNSUB)?adder_output:shift_logic;
+               if(word32)
+                       final_output=signExtend(final_output[31:0]);
+               if(inst_type==MEMORY && mem_access==Atomic) // TODO see if this can be avoided
+                       final_output=op1;
+               /*============================================ */
+               /*====== generate the effective address to jump to ====== */  
+               Bit#(`VADDR) branch_address=truncate(immediate_value)+pc;
+               Bit#(`VADDR) next_pc=pc+4;
+               Bit#(`VADDR) effective_address=0;
+               Bit#(2) new_state=prediction;
+               if(inst_type==JAL || inst_type==JALR)
+                       new_state='b11;
+               else if(final_output[0]==1)begin
+                       if(new_state<3)
+                               new_state=new_state+1;
+               end
+               else begin
+                       if(new_state>0)
+                               new_state=new_state-1;
+               end
+               Training_data#(`VADDR) bp_train = Training_data{pc:pc,branch_address:branch_address,state:new_state};
+               Maybe#(Training_data#(`VADDR)) training_data=tagged Invalid;
+               Maybe#(Bit#(`VADDR)) ras_push=tagged Invalid;
+
+               if(inst_type==BRANCH && final_output[0]==1)
+                       perfmonitors[`COND_BRANCH_TAKEN]=1;
+
+               if((inst_type==BRANCH && final_output[0]==1) || inst_type==JAL)
+                       effective_address=branch_address;
+               else if(inst_type==FENCEI || (inst_type==BRANCH && final_output[0]==0))
+                       effective_address=next_pc;
+               else begin
+                       effective_address=truncate(final_output);
+                       bp_train.branch_address=truncate(final_output);
+               end
+               if(inst_type==JAL || inst_type==JALR)
+                       final_output=signExtend(next_pc);
+               `ifdef simulate
+                       if(inst_type==BRANCH)
+                               final_output=0;
+               `endif
+               /*======================================================== */
+               /*==== Generate flush if prediction was wrong or FENCEI ========== */
+               if(inst_type==BRANCH || inst_type==JAL || ((rd != 'b00101 || rd!='b00001) && inst_type==JALR))
+                       training_data=tagged Valid bp_train;
+               Flush_type flush=None;
+               if((inst_type==BRANCH || inst_type==JAL || inst_type==JALR) && effective_address!=npc)begin
+                       if(inst_type==BRANCH)
+                               perfmonitors[`COND_BRANCH_MISPREDICTED]=1;
+                       flush=AccessFlush;
+               end
+               else if(inst_type==FENCEI)
+                       flush=Fence;
+               if((inst_type==JAL||inst_type==JALR) &&& rd matches 'b00?01) // TODO put on RAS only if rd = ra
+                       ras_push=tagged Valid next_pc;
+               /*================================================================ */
+       Trap_type exception=tagged None;
+       if((inst_type==JALR || inst_type==JAL) && effective_address[1]!=0)
+               exception=tagged Exception Inst_addr_misaligned;
+       Execution_output result;
+               if(inst_type==MEMORY || inst_type==FENCE || inst_type == FENCEI)begin
+                       result= tagged MEMORY (Memout{
+                               address:final_output,
+                               memory_data:immediate_value,
+                               transfer_size:zeroExtend(funct3[1:0]),
+                               signextend:~funct3[2],
+                               mem_type:(inst_type==FENCE || inst_type==FENCEI)?Fence:mem_access
+                               `ifdef atomic ,atomic_op:{pack(word32),fn} `endif       });
+               end
+               else if(inst_type==SYSTEM_INSTR)begin
+                       result=tagged SYSTEM (CSRInputs{rs1:op1,rs2:op2,rs1_addr:immediate_value[16:12],funct3:funct3,csr_address:immediate_value[11:0]});      
+               end
+               else
+                       result=tagged RESULT (Arithout{aluresult:final_output,fflags:0});
+               return tuple7(result,effective_address,flush, training_data,ras_push,exception,perfmonitors);
+       endfunction
+
+//     module mkTb(Empty);
+//
+//     rule test_alu;
+//             Bit#(64) op1='h8000000000004123;
+//             Int#(64) in1=unpack(op1);
+//             Bit#(64) op2='h8000000000004123;
+//             let {x,ea,flush}<-fn_alu(`FNSNE,op1,op2,'d0,'d0,BRANCH,'h800,'d3,Load,False);
+//             //$display("Output is: :%h Excepted: %h",x,(op1!=op2));
+//             $finish(0);
+//     endrule
+//     endmodule
+       
+endpackage
diff --git a/src/core/branchpredictor.bsv b/src/core/branchpredictor.bsv
new file mode 100644 (file)
index 0000000..68cd7c9
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+Copyright (c) 2013, IIT Madras
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+*  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+*  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+*  Neither the name of IIT Madras  nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+*/
+package branchpredictor;
+       /*===== Pacakge imports ===== */
+       import BRAMCore::*;
+       import FIFO::*;
+       import FIFOF::*;
+       import SpecialFIFOs::*;
+       import LFSR::*;
+       import ConfigReg::*;
+       import DReg::*;
+               import Connectable::*;
+               import GetPut::*;
+       /*===== project imports==== */
+       import defined_types::*;
+       `include "defined_parameters.bsv"
+       /*========================= */
+
+       interface Ifc_branchpredictor;
+               interface Put#(Tuple2#(Bit#(3),Bit#(`VADDR))) send_prediction_request;
+               interface Get#(Tuple4#(Bit#(3),Bit#(`VADDR),Bit#(`VADDR),Bit#(2))) prediction_response;
+               method Action training (Maybe#(Training_data#(`VADDR)) training_data);
+       endinterface
+
+       (*synthesize*)
+       module mkbranchpredictor(Ifc_branchpredictor);
+               let btb_sizebits=valueOf(TLog#(`BTB_DEPTH));
+               let tag_sizebits=(`VADDR-(btb_sizebits+2));
+               let max_size=tag_sizebits+3;
+               BRAM_DUAL_PORT#(Bit#(TLog#(`BTB_DEPTH)),Bit#(`VADDR)) rg_target_addr <- mkBRAMCore2(valueOf(`BTB_DEPTH),False);
+               BRAM_DUAL_PORT#(Bit#(TLog#(`BTB_DEPTH)),Bit#(TAdd#(3,TSub#(TSub#(`VADDR, TLog#(`BTB_DEPTH)),2)))) rg_tag <- mkBRAMCore2(valueOf(`BTB_DEPTH),False);
+               Reg#(Bit#(TSub#(TSub#(`VADDR,TLog#(`BTB_DEPTH)),2))) training_tag <-mkReg(0);
+               Reg#(Bit#(TLog#(`BTB_DEPTH))) training_index <-mkReg(0);
+               Reg#(Bool) rg_initialize <-mkReg(True);
+               Reg#(Bit#(TAdd#(1,TLog#(`BTB_DEPTH)))) rg_index<-mkReg(0);
+               FIFOF#(Tuple2#(Bit#(3),Bit#(`VADDR))) capture_prediction_request <-mkLFIFOF();
+               rule initialize_brams(rg_initialize);
+                       rg_tag.b.put(True,truncate(rg_index),{3'b001,'d0});     
+                       if(rg_index==(`BTB_DEPTH-1))begin
+                               rg_initialize<=False;
+                               rg_index<=0;
+                       end
+                       else
+                               rg_index<=rg_index+1;
+               endrule
+               interface send_prediction_request = interface Put 
+                       method Action put(Tuple2#(Bit#(3),Bit#(`VADDR)) req)if(!rg_initialize);
+                               let {epoch,vaddress} = req;
+                               `ifdef verbose $display($time,"\tBPU: Prediction Request for Address: %h",vaddress); `endif
+                               rg_target_addr.a.put(False,vaddress[btb_sizebits+1:2],?);
+                               rg_tag.a.put(False,vaddress[btb_sizebits+1:2],?);
+                               capture_prediction_request.enq(req);
+                       endmethod
+               endinterface;
+               interface prediction_response = interface Get
+                       method ActionValue#(Tuple4#(Bit#(3),Bit#(`VADDR),Bit#(`VADDR),Bit#(2))) get if(!rg_initialize);
+                               let {epoch,vaddress} = capture_prediction_request.first;
+                               Bit#(`VADDR) target_address=rg_target_addr.a.read;
+                               let info=rg_tag.a.read;
+                               Bit#(TSub#(TSub#(`VADDR,btb_sizebits),2)) tag=info[tag_sizebits-1:0];
+                               Bit#(TSub#(TSub#(`VADDR, TLog#(`BTB_DEPTH)),2)) cpu_tag=vaddress[`VADDR-1:btb_sizebits+2];
+                               Bit#(1) valid=info[tag_sizebits+2];
+                               Bit#(1) tag_match=pack(tag==cpu_tag)&valid;
+                               Bit#(2) state=(tag_match==1)?info[tag_sizebits+1:tag_sizebits]:'b01;
+                               let x= tuple4(epoch,vaddress,target_address,state);
+                               capture_prediction_request.deq;
+                               return x;
+                       endmethod
+               endinterface;
+               method Action training (Maybe#(Training_data#(`VADDR)) training_data)if(!rg_initialize); //to train the bpu;
+                       if(training_data matches tagged Valid .td)begin
+                               let addr=td.branch_address;
+                               Bit#(TLog#(`BTB_DEPTH)) index=td.pc[btb_sizebits+1:2];
+                               Bit#(TSub#(TSub#(`VADDR, TLog#(`BTB_DEPTH)),2)) tag=td.pc[`VADDR-1:btb_sizebits+2];
+                               `ifdef verbose $display($time,"\tBPU: training for PC: %h JumpAddr: %h index: %d State:",td.pc,addr,index,fshow(td.state)); `endif
+                               rg_target_addr.b.put(True,td.pc[btb_sizebits+1:2],addr);
+                               rg_tag.b.put(True,td.pc[btb_sizebits+1:2],{1,td.state,tag});
+                       end
+               endmethod
+       endmodule
+endpackage
diff --git a/src/core/core.bsv b/src/core/core.bsv
new file mode 100644 (file)
index 0000000..54902ff
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+Copyright (c) 2013, IIT Madras
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+*  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+*  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+*  Neither the name of IIT Madras  nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+*/
+package core;
+
+       /* ======== Package imports ======= */
+       import Vector                                                   :: *;
+       import FIFO                                                             :: *;
+       import ConfigReg                                        ::*;
+       import Connectable                              :: *;
+       /*================================== */
+
+       /*========= Project imports ======== */
+       `include "defined_parameters.bsv"
+       import defined_types                    ::*;
+       import Semi_FIFOF                                       ::*;
+       import AXI4_Types               :: *;
+       import AXI4_Fabric              :: *;
+       import riscv                                    :: *;
+       import imem                             ::*;
+       import dmem                             ::*;
+       import GetPut                   ::*;
+       import PTWalk                   ::*;
+       /*================================== */
+
+
+       interface Ifc_external_interrupt;
+               method Action enqueueInterrupts;
+       endinterface
+
+       interface Ifc_core_AXI4;
+               interface AXI4_Master_IFC#(`PADDR, `Reg_width, `USERSPACE) imem_master;
+               interface AXI4_Master_IFC#(`PADDR, `Reg_width, `USERSPACE) dmem_master;
+               method Action set_external_interrupt(Tuple2#(Bool,Bool) i);
+               method Action boot_sequence(Bit#(1) bootseq);
+               /* =========================== Debug Interface ===================== */
+               `ifdef Debug
+                       method Action reset;
+                       method Action                                                           run_continue;                                                    // Execute all instructions until the end of instruction stream
+                       method Bool                                                                     reset_complete;
+               method Action                                                           stop;                                                                            // Stop CPU
+               method Bool halted ();
+               method Bit#(`Reg_width)                 read_igpr (Bit#(5) r);                           // Read a General-Purpose Register
+               method Action                                                           write_igpr (Bit#(5) r, Bit#(`Reg_width) d);      // Write into a General-Purpose Register
+                       `ifdef spfpu
+               method Bit#(`Reg_width)                 read_fgpr (Bit#(5) r);                           // Read a General-Purpose Register
+               method Action                                                           write_fgpr (Bit#(5) r, Bit#(`Reg_width) d);      // Write into a General-Purpose Register
+                       `endif
+               method ActionValue#(Bit#(`Reg_width))                   rw_csr (Bit#(12) r, Bool write, Bit#(`Reg_width) data);                          // Read a General-Purpose Register
+               `endif
+               `ifdef CLINT
+                       method Action clint_msip(Bit#(1) intrpt);
+                       method Action clint_mtip(Bit#(1) intrpt);
+                       method Action clint_mtime(Bit#(`Reg_width) c_mtime);
+               `endif
+               /*-========================================================================== */
+       endinterface
+
+       typedef enum {Handling_Dcache,Handling_Icache,Idle,Handling_Uncacheable} Controller_State deriving (Bits, Eq, FShow);
+
+       //(*mutually_exclusive="mkConnectionGetPut_7,mkConnectionGetPut_8")
+       `ifdef MMU (*preempts="dtlb_to_ptw,itlb_to_ptw"*) `endif
+       //`ifdef MMU (*preempts="mkConnectionGetPut_4,mkConnectionGetPut_3"*) `endif
+       (*synthesize*)
+       module mkcore_AXI4#(Bit#(`VADDR) reset_vector)(Ifc_core_AXI4);
+               Ifc_riscv riscv <-mkriscv(reset_vector);
+               AXI4_Master_Xactor_IFC #(`PADDR,`Reg_width,`USERSPACE) imem_xactor <- mkAXI4_Master_Xactor;
+               AXI4_Master_Xactor_IFC #(`PADDR,`Reg_width,`USERSPACE) dmem_xactor <- mkAXI4_Master_Xactor;
+               Ifc_imem imem <-mkimem();
+               Ifc_dmem dmem <- mkdmem;
+               Ifc_PTWalk#(`ADDR, `VADDR, 56, `PADDR, `ASID, `OFFSET) ptw <- mkPTWalk;
+               Wire#(Bit#(`Reg_width)) wr_pte <- mkWire();
+               Reg#(Bool) rg_serve_dTLB <- mkReg(False);
+
+               mkConnection(riscv.request_to_imem,imem.request_from_core);
+               mkConnection(imem.instruction_response_to_core,riscv.instruction_response_from_imem);
+               mkConnection(riscv.request_to_dmem, dmem.request_from_cpu);
+               mkConnection(dmem.response_to_cpu, riscv.response_from_dmem);
+               `ifdef MMU
+                       rule itlb_to_ptw;
+                               let x <- imem.to_PTW.get;
+                               ptw.frm_TLB.put(x);
+                               rg_serve_dTLB <=False;
+                       endrule
+                       rule dtlb_to_ptw;
+                               let x <- dmem.to_PTW.get;
+                               ptw.frm_TLB.put(x);
+                               rg_serve_dTLB <=True;
+                       endrule
+                       rule ptw_to_itlb(!rg_serve_dTLB);
+                               let x <- ptw.to_TLB.get;
+                               imem.refill_TLB.put(x);
+                       endrule
+                       rule ptw_to_dtlb(rg_serve_dTLB);
+                               let x <- ptw.to_TLB.get;
+                               dmem.refill_TLB.put(x);
+                       endrule
+                       //mkConnection(imem.to_PTW, ptw.frm_TLB);
+                       //mkConnection(dmem.to_PTW, ptw.frm_TLB);
+                       //mkConnection(ptw.to_TLB, imem.refill_TLB);
+                       //mkConnection(ptw.to_TLB, dmem.refill_TLB);
+               `endif
+               mkConnection(imem.prediction_response,riscv.prediction_response);
+               mkConnection(riscv.send_prediction_request,imem.send_prediction_request);
+               rule connect_training;
+                       imem.training(riscv.training_data);
+               endrule
+//             (*conflict_free="connect_flush_to_imem,connect_flush_to_dmem"*)
+//             rule connect_flush_to_imem;
+//                     Translation_type page_type = Execution;
+//                     if(riscv.flush_imem!=None) begin
+//                             ptw.flush(page_type);
+//                     end
+//             endrule
+               rule connect_flush_to_dmem;
+                       Translation_type page_type = Load;
+                       if(riscv.flush_dmem)
+                               dmem.flush();
+               //      if(riscv.flush_dmem) begin
+               //              ptw.flush(page_type);
+               //      end
+               endrule
+
+               `ifdef MMU
+                       //rule fence_iTLB;
+                       //      `ifdef verbose $display($time ,"\tCORE: iTLB is being flushed"); `endif
+                       //      imem.fence_itlb(dmem.fence_itlb);
+                       //endrule
+                       rule send_permissions_to_tlb;
+                               ptw.satp_frm_csr(riscv.send_satp);
+                               imem.translation_protection_frm_csr(riscv.mmu_cache_disable[0],
+                                                                                                                               riscv.perm_to_TLB,
+                                                                                                                               riscv.send_satp[`Reg_width-1:`Reg_width-`ASID-4]);
+                               dmem.translation_protection_frm_csr(riscv.mmu_cache_disable[0],
+                                                                                                                               riscv.perm_to_TLB,
+                                                                                                                               riscv.send_satp[`Reg_width-1:`Reg_width-`ASID-4]);
+                       endrule
+                       rule send_pte_pointer;
+                               let x <- ptw.ifc_memory.send_PTE_pointer;
+                               dmem.get_pte_pointer(x);
+                       endrule 
+                       rule get_pte_entry;
+                               let x <- dmem.send_pte;
+                               wr_pte <= x;
+                       endrule 
+                       rule send_pte_entry;
+                               ptw.ifc_memory.get_PTE(wr_pte);
+                       endrule
+                       rule fence_tlbs;
+                               dmem.fence_dtlb(riscv.fence_tlbs);
+                               imem.fence_itlb(riscv.fence_tlbs);
+                       endrule
+               `endif
+               rule fence_stall_icache;
+                       imem.stall_fetch(dmem.stall_fetch);
+               endrule
+               Reg#(Bool) rg_update_a_bit <- mkReg(False);
+               Reg#(Bool) rg_update_b_bit <- mkReg(False);
+               Reg#(Maybe#(Bit#(TMul#(8,TMul#(`DCACHE_WORD_SIZE,`DCACHE_BLOCK_SIZE))))) rg_data_line <-mkReg(tagged Invalid);
+               Reg#(Bit#(8)) rg_burst_count<-mkReg(0);
+               Reg#(Bool) rg_wait_for_response[2]<-mkCReg(2,False);
+               rule check_read_request_to_memory_from_dcache;
+                       let info<-dmem.request_to_memory_read;
+                       Bit#(2) arburst=2;
+                       if(info.burst_length==1)
+                               arburst=1;
+                       let read_request = AXI4_Rd_Addr {araddr: truncate(info.address), aruser: 0, arlen: info.burst_length-1, arsize: zeroExtend(info.transfer_size), arburst: arburst, arid:'d0}; // arburst: 00-FIXED 01-INCR 10-WRAP
+                       dmem_xactor.i_rd_addr.enq(read_request);        
+                       `ifdef verbose $display($time,"\tCORE: Sending Read Request from DCACHE for Address: %h Burst Length: %h",info.address,info.burst_length); `endif
+               endrule
+               rule check_write_request_to_memory_from_dcache(rg_data_line matches tagged Invalid &&& !rg_wait_for_response[1]);
+                       let info<-dmem.request_to_memory_write;
+                       /*=== Need to shift the data apprpriately while sending write requests===== */
+                       Bit#(`Reg_width) actual_data=info.data_line[`Reg_width-1:0];
+                       Bit#(8) write_strobe=info.transfer_size==0?8'b1:info.transfer_size==1?8'b11:info.transfer_size==2?8'hf:8'hff;
+                       if(info.transfer_size!=3)begin                  // 8-bit write;
+                               write_strobe=write_strobe<<(info.address[`byte_offset:0]);
+                       end
+//                     info.address[2:0]=0; // also make the address 64-bit aligned
+                       /*========================================================================= */
+                       let aw = AXI4_Wr_Addr {awaddr: truncate(info.address), awuser:0, awlen: info.burst_length-1, awsize: zeroExtend(info.transfer_size), awburst: 'b01, awid:'d0}; // arburst: 00-FIXED 01-INCR 10-WRAP
+                       let w  = AXI4_Wr_Data {wdata:  actual_data, wstrb: write_strobe, wlast:info.burst_length>1?False:True, wid:'d0};
+                       dmem_xactor.i_wr_addr.enq(aw);
+                       dmem_xactor.i_wr_data.enq(w);
+                       `ifdef verbose $display($time,"\tCORE: Sending Write Request from DCACHE for  Address: %h BurstLength: %h Data: %h WriteStrobe: %b",info.address,info.burst_length,info.data_line, write_strobe); `endif
+                       if(info.burst_length>1)begin // only enable the next rule when doing a line write in burst mode.
+                       rg_data_line<=tagged Valid (info.data_line>>`Reg_width);
+                       rg_burst_count<=rg_burst_count+1;
+                       end
+                       rg_wait_for_response[1]<=True;
+               endrule
+               rule send_burst_write_data(rg_data_line matches tagged Valid .data_line);
+                       /*==  Since this is going to always be a line write request in burst mode No need of shifting data and address=== */
+                       let w  = AXI4_Wr_Data {wdata:  truncate(data_line), wstrb: 8'hff , wlast:(rg_burst_count==`DCACHE_BLOCK_SIZE-1), wid:'d0};
+                       dmem_xactor.i_wr_data.enq(w);
+                       `ifdef verbose $display($time,"\tCORE: Sending DCACHE Write Data: %h Burst: %d",data_line,rg_burst_count); `endif
+                       if(rg_burst_count==`DCACHE_BLOCK_SIZE-1)begin
+                               rg_burst_count<=0;
+                               rg_data_line<=tagged Invalid;
+                       end
+                       else begin
+                               rg_data_line<=tagged Valid (data_line>>`Reg_width);
+                               rg_burst_count<=rg_burst_count+1;
+                       end
+               endrule
+               rule check_read_request_to_memory_from_icache;
+                       let info <-imem.request_to_memory;
+                       let read_request = AXI4_Rd_Addr {araddr: truncate(info.address), aruser: 0, arlen: info.burst_length-1, arsize: info.transfer_size, arburst: 'b10, arid:'d1}; // arburst: 00-FIXED 01-INCR 10-WRAP
+                       imem_xactor.i_rd_addr.enq(read_request);        
+                       `ifdef verbose $display($time,"\tCORE: Sending Read Request from ICACHE for Address: %h Burst Length: %h",info.address,info.burst_length); `endif
+               endrule
+               rule send_read_response_from_memory_to_dcache(dmem_xactor.o_rd_data.first.rid == 'd0); 
+                       let response <- pop_o (dmem_xactor.o_rd_data);  
+                       let bus_error_from_memory = (response.rresp==AXI4_OKAY) ? 0 : 1;
+                       `ifdef verbose $display($time,"\tCORE: Sending Response to DCACHE: ",fshow(response)); `endif
+                       dmem.response_from_memory_read(From_Memory{data_line:response.rdata,bus_error:bus_error_from_memory,last_word:response.rlast});
+               endrule
+               rule send_read_response_from_memory_to_icache(imem_xactor.o_rd_data.first.rid == 'd1); 
+                       let response <- pop_o (imem_xactor.o_rd_data);  
+                       let bus_error_from_memory = (response.rresp==AXI4_OKAY) ? 0 : 1;
+                       `ifdef verbose $display($time,"\tCORE: Sending Response to ICACHE: ",fshow(response)); `endif
+                       imem.response_from_memory(From_Memory{data_line:response.rdata,bus_error:bus_error_from_memory, last_word:response.rlast});
+               endrule
+               rule send_write_response_to_dcache(rg_wait_for_response[0] && dmem_xactor.o_wr_resp.first.bid == 'd0);
+                       let response<-pop_o(dmem_xactor.o_wr_resp);
+                       let bus_error_from_memory = (response.bresp==AXI4_OKAY) ? 0 : 1;
+                       `ifdef verbose $display($time,"\tCORE: Received Write Response:",fshow(response)); `endif
+                       dmem.response_from_memory_write(From_Memory{data_line:0,bus_error:bus_error_from_memory,last_word:True});
+                       rg_wait_for_response[0]<=False;
+               endrule
+               
+               interface imem_master = imem_xactor.axi_side;
+               interface dmem_master = dmem_xactor.axi_side;
+               `ifdef Debug
+                       method run_continue=riscv.run_continue;
+                       method reset_complete=riscv.reset_complete;
+                       method stop=riscv.stop;
+                       method halted=riscv.halted;
+                       method Bit#(`Reg_width)read_igpr(Bit#(5) r);
+                               return riscv.read_debug_igpr(r);
+                       endmethod
+                       method Action write_igpr(Bit#(5) r, Bit#(`Reg_width)d);
+                               riscv.write_debug_igpr(r,d);
+                       endmethod
+                       `ifdef spfpu
+                       method Bit#(`Reg_width) read_fgpr(Bit#(5) r);
+                               return riscv.read_debug_fgpr(r);
+                       endmethod
+                       method Action write_fgpr(Bit#(5) r, Bit#(`Reg_width)d);
+                               riscv.write_debug_fgpr(r,d);
+                       endmethod
+                       `endif
+               method ActionValue#(Bit#(`Reg_width))   rw_csr (Bit#(12) r, Bool write, Bit#(`Reg_width) data)=riscv.rw_csr(r,write,data);
+                       method Action reset=riscv.reset;
+               `endif
+               method Action boot_sequence(Bit#(1) bootseq)=riscv.boot_sequence(bootseq);
+               method Action set_external_interrupt(Tuple2#(Bool,Bool) i)=riscv.set_external_interrupt(i);
+               `ifdef CLINT
+                       method Action clint_msip(Bit#(1) intrpt)=riscv.clint_msip(intrpt);
+                       method Action clint_mtip(Bit#(1) intrpt)=riscv.clint_mtip(intrpt);
+                       method Action clint_mtime(Bit#(`Reg_width) c_mtime)=riscv.clint_mtime(c_mtime);
+               `endif
+       endmodule
+endpackage
diff --git a/src/core/csr.bsv b/src/core/csr.bsv
new file mode 100644 (file)
index 0000000..704db61
--- /dev/null
@@ -0,0 +1,1129 @@
+/*
+Copyright (c) 2013, IIT Madras
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+*  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+*  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+*  Neither the name of IIT Madras  nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+*/
+package csr;
+
+/*  ############################ changes from 1.9.1 ############################
+               1. base field in misa is changed to readOnlyfield of mxl as per the encoding
+                        and the same is reflected in sxl and uxl fields of mstatus
+               2. change of fields in mstatus.
+*/
+
+       import defined_types::*;
+       `include "defined_parameters.bsv"
+       import ConfigReg::*;
+       import GetPut            ::*;
+       import ConcatReg ::*;
+       import Vector::*;
+
+       interface Ifc_csr;
+               method Bit#(3) roundingmode;
+               method Action set_external_interrupt(Tuple2#(Bool,Bool) i);
+               method Action flush;
+               (*always_ready,always_enabled*)
+               method Action boot_sequence(Bit#(1) bootseq);
+               /*======= MMU related interfaces ===== */
+               `ifdef MMU
+                       method Bit#(`Reg_width) send_satp;
+                       method Chmod perm_to_TLB;
+               `endif
+               method Bit#(`Reg_width) mmu_cache_disable;
+               /*=========================================== */
+               /*=========== Debug related interfaces ====== */
+               `ifdef Debug
+                       method Bool halted;
+                       method ActionValue#(Bit#(`Reg_width)) rw_debug_csr(Bit#(12) r, Bool write, Bit#(`Reg_width) data);
+                       method TriggerData load_triggerdata;
+                       method TriggerData store_triggerdata;
+                       method Bool step_now;
+                       method Bool reset_mode;
+               `endif
+               /*=========================================== */
+               method ActionValue#(Tuple2#(Bit#(3),Trap_type)) check_for_trap(`ifdef Debug Bool haltreq, Bool resumereq, Bool resetreq, `endif Bit#(`VADDR) pc, Bit#(32) instruction); 
+       method ActionValue#(Tuple4#(Bool,Bit#(`VADDR),Bit#(`Reg_width),Bool)) system_instruction(WriteBackType wbdata ,Bit#(`VADDR) pc, Bit#(`PERFMONITORS) perfmonitor_incr `ifdef simulate , Bit#(32) instruction, Operand_type rd_type, Bit#(5) destination `endif );
+               method ActionValue#(Tuple2#(Bit#(`VADDR), Bool)) take_trap(Trap_type exception, Bit#(3) lv_debugcause, Bit#(`VADDR) pc, Bit#(`VADDR) badaddr);
+               method Bit#(`Reg_width) misa;
+               method Bit#(2) powercontrol;
+               method Action poweracknowledge(Bit#(2) pa);
+               `ifdef CLINT
+                       method Action clint_msip(Bit#(1) intrpt);
+                       method Action clint_mtip(Bit#(1) intrpt);
+                       method Action clint_mtime(Bit#(`Reg_width) c_mtime);
+               `endif
+    method Bit#(2) inferred_xlen;
+  endinterface
+
+  function String csr_funct(Bit#(3) funct3);
+               case(funct3)
+                       'd1:return      "CSRRW";
+                       'd2:return  "CSRRS";
+                       'd3:return  "CSRRC";
+                       'd5:return  "CSRRWI" ;
+                       'd6:return  "CSRRSI"; 
+                       'd7:return  "CSRRCI" ;
+                       default: return "NOIDEA";
+               endcase
+  endfunction
+
+  function Reg#(t) readOnlyReg(t r);
+    return (interface Reg;
+       method t _read = r;
+       method Action _write(t x) = noAction;
+    endinterface);
+  endfunction
+
+  function Reg#(Bit#(a)) extInterruptReg(Reg#(Bit#(a)) r1, Reg#(Bit#(a)) r2);
+    return (interface Reg;
+            method Bit#(a) _read = r1 | r2;
+            method Action _write(Bit#(a) x); 
+               r1._write(x);
+                               endmethod
+        endinterface);
+  endfunction
+
+  function Reg#(t) writeSideEffect(Reg#(t) r, Action a);
+    return (interface Reg;
+            method t _read = r._read;
+            method Action _write(t x);
+                r._write(x);
+                a;
+            endmethod
+        endinterface);
+endfunction
+
+  (*synthesize*)
+       (*conflict_free="take_trap, set_external_interrupt"*)
+  (*conflict_free="check_for_trap,system_instruction"*)
+  module mkcsr(Ifc_csr);
+
+       Reg#(Bool) rg_initialize[2]<-mkCReg(2,False);
+       Reg#(Bit#(12)) rg_index<-mkReg(0);
+       `ifdef simulate
+               Reg#(Bool) wr_endsimulation <-mkReg(False);
+           Reg#(Bit#(1)) rg_cnt <-mkReg(0);
+           let dump <- mkReg(InvalidFile) ;
+           rule open_file(rg_cnt==0);
+                                       String dumpFile = "rtl.dump" ;
+               File lfh <- $fopen( dumpFile, "w" ) ;
+               if ( lfh == InvalidFile )begin
+                   `ifdef verbose $display("cannot open %s", dumpFile); `endif
+                   $finish(0);
+               end
+               dump <= lfh ;
+               rg_cnt <= 1 ;
+           endrule
+       `endif
+  /////////////////////////////// Machine level register /////////////////////////
+  // Current Privilege Level
+       Reg#(Privilege_mode) rg_prv <- mkConfigReg(Machine); // resets to machine mode
+
+       
+       Reg#(Bit#(`Reg_width)) csr_mvendorid = readOnlyReg(0);
+       Reg#(Bit#(`Reg_width)) csr_marchid = readOnlyReg(0);
+       Reg#(Bit#(`Reg_width)) csr_mimpid = readOnlyReg(0);
+       Reg#(Bit#(`Reg_width)) csr_mhartid = readOnlyReg(0);
+       //misa fields
+       Reg#(Bit#(2))  rg_mxl           <- mkReg(2);
+       Bit#(26) temp_misa='d0;
+       temp_misa[8]=1;
+       temp_misa[20]=1;
+       `ifdef atomic   temp_misa[0]=1; `endif
+       `ifdef dpfpu    temp_misa[3]=1; `endif
+       `ifdef spfpu    temp_misa[5]=1; `endif
+       `ifdef muldiv   temp_misa[12]=1; `endif
+       `ifdef MMU              temp_misa[18]=1; `endif
+       `ifdef Openocd
+               Reg#(Bit#(26)) rg_misa  <- mkReg(temp_misa);
+       `else 
+               Reg#(Bit#(26)) rg_misa  <- mkReg(`MISA_BITS);
+       `endif
+       Reg#(Bit#(`Reg_width)) csr_misa = concatReg3(rg_mxl,readOnlyReg(0),rg_misa);
+   
+  // trap vector fields (same as CSR without bottom 2 bits)
+       Reg#(Bit#(2))  rg_mode_m                <- mkReg(0); //default value 0 if pc to base or 1 if pc to base + 4xcause
+       Reg#(Bit#(TSub#(`PADDR,2))) rg_mtvec <- mkReg(`MTVEC_DEFAULT);
+       Reg#(Bit#(`Reg_width)) csr_mtvec=concatReg3(readOnlyReg(0),rg_mtvec, rg_mode_m);
+
+  // mstatus fields
+       Reg#(Bit#(1)) rg_tsr    <- mkReg(0); // WARL
+       Reg#(Bit#(1)) rg_tw             <- mkReg(0); // WARL
+       Reg#(Bit#(1)) rg_tvm    <- mkReg(0); // WARL
+       Reg#(Bit#(1)) rg_mxr  <- mkReg(0); // Not required
+       Reg#(Bit#(1)) rg_sum  <- mkReg(0); // Not required
+       Reg#(Bit#(1)) rg_mprv <- mkReg(0);
+       Reg#(Bit#(2)) rg_xs             =  readOnlyReg(0);
+       Reg#(Bit#(2)) rg_fs             <- mkReg(2'b00);
+       Reg#(Bit#(2)) rg_mpp    <- mkReg(2'b0);
+       Reg#(Bit#(2)) rg_hpp    =  readOnlyReg(0);
+       Reg#(Bit#(1)) rg_spp    <-  mkReg(0);
+       Reg#(Bit#(1)) rg_mpie <- mkReg(0);
+       Reg#(Bit#(1)) rg_hpie =  readOnlyReg(0);
+       Reg#(Bit#(1)) rg_spie <- mkReg(0);
+       Reg#(Bit#(1)) rg_upie <- mkReg(0);
+       `ifdef Openocd
+               Reg#(Bit#(1)) rg_mie    <- mkReg(1);
+       `else
+               Reg#(Bit#(1)) rg_mie    <- mkReg(0);
+       `endif
+       Reg#(Bit#(1)) rg_hie    =  readOnlyReg(0);
+       Reg#(Bit#(1)) rg_sie    <- mkReg(0);
+       Reg#(Bit#(1)) rg_uie    <- mkReg(0);
+       Reg#(Bit#(1)) rg_sd             =  readOnlyReg(pack((rg_xs == 2'b11) || (rg_fs == 2'b11)));
+       Reg#(Bit#(`Reg_width)) csr_mstatus =  concatReg24(
+           rg_sd,
+           readOnlyReg(0),
+           readOnlyReg(rg_mxl), readOnlyReg(rg_mxl),          //sxl and uxl fields are hardwired to mxl in misa
+           readOnlyReg(9'b0),
+                                        rg_tsr, rg_tw, rg_tvm,
+           rg_mxr, rg_sum, rg_mprv, // memory privilege
+           rg_xs, rg_fs, // coprocessor states
+           rg_mpp, rg_hpp, rg_spp, // previous privileges
+           rg_mpie, rg_hpie, rg_spie, rg_upie, // previous interrupt enables
+           rg_mie, rg_hie, rg_sie, rg_uie); // interrupt enables
+
+       // trap delegation fields
+       Reg#(Bit#(16)) rg_medeleg<-mkReg(0);
+       Reg#(Bit#(15)) rg_mideleg<-mkReg(0);
+       Reg#(Bit#(`Reg_width)) csr_medeleg = concatReg2(readOnlyReg(0),rg_medeleg);
+       Reg#(Bit#(`Reg_width)) csr_mideleg = concatReg2(readOnlyReg(0),rg_mideleg);
+
+       // mie fields
+       Reg#(Bit#(1)) rg_meie <- mkReg(0);
+       Reg#(Bit#(1)) rg_heie =  readOnlyReg(0);
+       Reg#(Bit#(1)) rg_seie <-  mkReg(0);
+       Reg#(Bit#(1)) rg_ueie <- mkReg(0);
+       Reg#(Bit#(1)) rg_mtie <- mkReg(0);
+       Reg#(Bit#(1)) rg_htie =  readOnlyReg(0);
+       Reg#(Bit#(1)) rg_stie <-  mkReg(0);
+       Reg#(Bit#(1)) rg_utie <- mkReg(0);
+       Reg#(Bit#(1)) rg_msie <- mkReg(0);
+       Reg#(Bit#(1)) rg_hsie =  readOnlyReg(0);
+       Reg#(Bit#(1)) rg_ssie <-  mkReg(0);
+       Reg#(Bit#(1)) rg_usie <- mkReg(0);
+       `ifdef Openocd
+               Reg#(Bit#(1)) rg_dhalt<-mkReg(1);
+               Reg#(Bit#(1)) rg_dresume<-mkReg(1);
+       `else
+               Reg#(Bit#(1)) rg_dhalt<-mkReg(0);
+               Reg#(Bit#(1)) rg_dresume<-mkReg(0);
+       `endif
+       Reg#(Bit#(1)) rg_dreset<-mkReg(0);
+       Reg#(Bit#(`Reg_width)) csr_mie     =  concatReg16(
+           readOnlyReg(0),
+                         rg_dreset,rg_dresume,rg_dhalt,
+           rg_meie, rg_heie, rg_seie, readOnlyReg(rg_ueie),
+           rg_mtie, rg_htie, rg_stie, readOnlyReg(rg_utie),
+           rg_msie, rg_hsie, rg_ssie, readOnlyReg(rg_usie));
+               Reg#(Bool) rg_nmi <- mkReg(True);
+
+       // mip fields
+       Reg#(Bit#(1)) rg_meip <-  mkConfigReg(0);
+       Reg#(Bit#(1)) rg_heip =  readOnlyReg(0);
+       Reg#(Bit#(1)) rg_seips <-   mkReg(0);
+       Reg#(Bit#(1)) rg_seipe <-   mkReg(0);
+       Reg#(Bit#(1)) rg_ueips <-   mkReg(0);
+       Reg#(Bit#(1)) rg_ueipe <-   mkReg(0);
+       Reg#(Bit#(1)) rg_seip =   extInterruptReg(rg_seips,rg_seipe);
+       Reg#(Bit#(1)) rg_ueip =   extInterruptReg(rg_ueips,rg_ueipe);
+       Reg#(Bit#(1)) rg_mtip <-mkReg(0);
+       Reg#(Bit#(1)) rg_htip =  readOnlyReg(0);
+       Reg#(Bit#(1)) rg_stip <-  mkReg(0);
+       Reg#(Bit#(1)) rg_utip <- mkReg(0);
+       Reg#(Bit#(1)) rg_msip <-  mkReg(0);
+       Reg#(Bit#(1)) rg_hsip =  readOnlyReg(0);
+       Reg#(Bit#(1)) rg_ssip <-  mkReg(0);
+       Reg#(Bit#(1)) rg_usip <- mkReg(0);
+       `ifdef RV64
+               Reg#(Bit#(`Reg_width)) csr_mcycle[2]<-mkCReg(2,0);
+               Reg#(Bit#(`Reg_width)) csr_minstret[2]<-mkCReg(2,0);
+       `else
+               Reg#(Bit#(`Reg_width)) csr_mcycle[2]<-mkCReg(2,0);
+               Reg#(Bit#(`Reg_width)) csr_minstret[2]<-mkCReg(2,0);
+               Reg#(Bit#(`Reg_width)) csr_mcycleh[2]<-mkCReg(2,0);
+               Reg#(Bit#(`Reg_width)) csr_minstreth[2]<-mkCReg(2,0);
+       `endif
+
+       // Machine Trap Handling
+       Reg#(Bit#(`Reg_width))           rg_mepc                <- mkReg(0);
+       Reg#(Bit#(`VADDR))       rg_mtval               <- mkReg(0);
+       Reg#(Bit#(`Reg_width)) csr_mscratch <- mkReg(0);
+       Reg#(Bit#(`Reg_width)) csr_mepc     = rg_mepc;
+  Reg#(Bit#(1)) rg_interrupt <- mkReg(0);
+  Reg#(Bit#(31)) rg_lower_cause <- mkReg(0);
+  Reg#(Bit#(32)) rg_upper_cause <- mkReg(0);
+       Reg#(Bit#(`Reg_width)) csr_mcause=   concatReg3(rg_interrupt, rg_upper_cause, rg_lower_cause);
+       Reg#(Bit#(`Reg_width)) csr_mtval                = concatReg2(readOnlyReg(0), rg_mtval);
+       Reg#(Bit#(`Reg_width)) csr_mip      =  concatReg13(
+           readOnlyReg(0),
+           readOnlyReg(rg_meip), readOnlyReg(rg_heip), rg_seip, rg_ueip,
+           readOnlyReg(rg_mtip), readOnlyReg(rg_htip), rg_stip, rg_utip,
+           readOnlyReg(rg_msip), readOnlyReg(rg_hsip), rg_ssip, rg_usip);
+  
+       Reg#(Bit#(`Reg_width)) mip      =  concatReg13(
+           readOnlyReg(0),
+           rg_meip, rg_heip, rg_seip, rg_ueip,
+           rg_mtip, rg_htip, rg_stip, rg_utip,
+           rg_msip, rg_hsip, rg_ssip, rg_usip);
+       //////////////////////////////////////////////////////////////////////////////////////////
+       ///////////////////////////////////Physical Memory Protection////////////////////////////
+       Reg#(Bit#(`Reg_width)) csr_pmpcfg0 <- mkReg(0);
+       `ifndef RV64
+       Reg#(Bit#(`Reg_width)) csr_pmpcfg1 <- mkReg(0);
+       `endif
+       Reg#(Bit#(`Reg_width)) csr_pmpcfg2 <- mkReg(0);
+       `ifndef RV64
+       Reg#(Bit#(`Reg_width)) csr_pmpcfg3 <- mkReg(0);
+       `endif
+
+       Reg#(Bit#(TSub#(`PADDR,2)))  rg_pmpaddr[`PMPADDREND - `PMPADDRSTART +1];
+       Reg#(Bit#(`Reg_width)) csr_pmpaddr[`PMPADDREND - `PMPADDRSTART +1];
+       for(Integer i=0; i<(`PMPADDREND - `PMPADDRSTART +1); i =i+1) begin
+               rg_pmpaddr[i] <- mkReg(0);
+               csr_pmpaddr[i] = concatReg2(readOnlyReg(0), rg_pmpaddr[i]);
+       end
+       //////////////////////////////////////////////////////////////////////////////////////////
+       // Counter enables
+       Reg#(Bit#(1)) rg_u_ir <- mkReg(0);
+       Reg#(Bit#(1)) rg_u_tm <- mkReg(0);
+       Reg#(Bit#(1)) rg_u_cy <- mkReg(0);
+       // Machine Counter Setup
+       Reg#(Bit#(32)) reg_mcounteren<-mkReg(0);
+       Reg#(Bit#(`Reg_width)) csr_mcounteren=concatReg2(readOnlyReg(32'd0),reg_mcounteren);
+       Reg#(Bit#(1)) rg_boot_seq<-mkReg(0);
+       Reg#(Bit#(`Reg_width)) csr_boot_seq =concatReg2(readOnlyReg(0),readOnlyReg(rg_boot_seq));
+       Reg#(Bit#(2)) power_control_out <-mkReg(0);
+       Reg#(Bit#(2)) power_control_in <-mkReg(0);
+       Reg#(Bit#(`Reg_width)) csr_power_control = concatReg3(readOnlyReg(0),readOnlyReg(power_control_in),power_control_out);
+
+       //////////////////////////////////////////////////////////////////////////////////////////
+       //////////////////////////////SUPERVISOR LEVEL REGISTERS//////////////////////////////////
+`ifdef MMU
+       Reg#(Bit#(`Reg_width)) csr_sstatus =  concatReg20(
+                rg_sd,
+                readOnlyReg(0), readOnlyReg(rg_mxl), readOnlyReg(12'b0), //uxl field
+                rg_mxr, rg_sum, readOnlyReg(1'b0), // memory privilege // 
+                rg_xs, rg_fs, // coprocessor states 
+                readOnlyReg(2'b0), readOnlyReg(2'b0), rg_spp, // previous privileges
+                readOnlyReg(1'b0), readOnlyReg(1'b0), rg_spie, rg_upie, // previous interrupt enables
+                readOnlyReg(1'b0), readOnlyReg(1'b0), rg_sie, rg_uie); // interrupt enables
+
+       Reg#(Bit#(12)) rg_sedeleg<-mkReg(0);
+       Reg#(Bit#(15)) rg_sideleg<-mkReg(0);
+       Reg#(Bit#(`Reg_width)) csr_sedeleg = concatReg2(readOnlyReg(0),rg_sedeleg);
+       Reg#(Bit#(`Reg_width)) csr_sideleg = concatReg2(readOnlyReg(0),rg_sideleg);
+
+       Reg#(Bit#(`Reg_width)) csr_sie     =  concatReg13(
+           readOnlyReg(0),
+           readOnlyReg(1'b0), readOnlyReg(1'b0), rg_seie, readOnlyReg(rg_ueie),
+           readOnlyReg(1'b0), readOnlyReg(1'b0), rg_stie, readOnlyReg(rg_utie),
+           readOnlyReg(1'b0), readOnlyReg(1'b0), rg_ssie, readOnlyReg(rg_usie));
+
+       Reg#(Bit#(2))  rg_mode_s                <- mkReg(0); //default value 0 if pc to base or 1 if pc to base + 4xcause
+       Reg#(Bit#(TSub#(`Reg_width,2))) rg_stvec <- mkReg(`STVEC_DEFAULT);
+  Reg#(Bit#(`Reg_width)) csr_stvec=concatReg2(rg_stvec,rg_mode_s);
+  Reg#(Bit#(32)) rg_scounteren <- mkReg(0);
+  Reg#(Bit#(`Reg_width)) csr_scounteren = concatReg2(readOnlyReg(0),rg_scounteren);
+
+       //Supervisor Trap Handling Register
+       Reg#(Bit#(`VADDR)) rg_stval                     <- mkReg(0);
+       Reg#(Bit#(`Reg_width)) csr_sscratch <- mkReg(0);
+   Reg#(Bit#(`Reg_width)) csr_sepc     <- mkReg(0);
+       Reg#(Bit#(`Reg_width)) csr_scause   <- mkReg(0);
+       Reg#(Bit#(`Reg_width)) csr_stval                = concatReg2(readOnlyReg(0), rg_stval);
+       Reg#(Bit#(`Reg_width)) csr_sip      =  concatReg13(
+           readOnlyReg(0),
+                                        readOnlyReg(1'b0), readOnlyReg(1'b0), readOnlyReg(rg_seip), rg_ueip,
+           readOnlyReg(1'b0), readOnlyReg(1'b0), readOnlyReg(rg_stip), readOnlyReg(rg_utip),
+           readOnlyReg(1'b0), readOnlyReg(1'b0), rg_ssip, readOnlyReg(rg_usip));
+
+       //Supervisor Protection and Translation
+       Reg#(Bit#(`Reg_width)) csr_satp         <- mkReg(0);
+`endif
+  //////////////////////////////////////////////////////////////////////////////////////////
+  //////////////////////////////// User level registers ///////////////////////////////////
+       `ifdef RV64
+               Reg#(Bit#(`Reg_width)) csr_uinstret=readOnlyReg(csr_minstret[1]);
+               Reg#(Bit#(`Reg_width)) csr_ucycle=readOnlyReg(csr_mcycle[1]);
+       `else
+               Reg#(Bit#(`Reg_width)) csr_uinstret=readOnlyReg(csr_minstret[1]);
+               Reg#(Bit#(`Reg_width)) csr_ucycle=readOnlyReg(csr_mcycle[1]);
+               Reg#(Bit#(`Reg_width)) csr_uinstreth=readOnlyReg(csr_minstreth[1]);
+               Reg#(Bit#(`Reg_width)) csr_ucycleh=readOnlyReg(csr_mcycleh[1]);
+       `endif
+
+       Reg#(Bit#(`Reg_width)) rg_clint_mtime <-mkReg(0);
+       Reg#(Bit#(5)) rg_fflags<-mkReg(0);
+       Reg#(Bit#(3)) rg_frm<-mkReg(0);
+       Reg#(Bit#(`Reg_width)) csr_fcsr = writeSideEffect(concatReg3(readOnlyReg(0),rg_frm,rg_fflags),rg_fs._write(2'b11));
+       Reg#(Bit#(`Reg_width)) csr_fflags=writeSideEffect(concatReg2(readOnlyReg(0),rg_fflags),rg_fs._write(2'b11));
+       Reg#(Bit#(`Reg_width)) csr_frm =  writeSideEffect(concatReg2(readOnlyReg(0),rg_frm),rg_fs._write(2'b11));
+       Reg#(Bit#(4))                            rg_memse <- mkReg(0); //0th-bit set -> immu disable,1th-bit set -> icache,2nd-bit -> dmmu, 3rd bit -> dcache 
+       Reg#(Bit#(`Reg_width)) csr_memse = concatReg2(readOnlyReg(0),rg_memse);  
+
+  //////////////////////////////////////////////////////////////////////////////////////////
+       ///////////////////////////////////////// PErformance Counters //////////////////////////
+       `ifdef perf
+       Array#(Reg#(Bit#(64))) csr_mhpmcounter[`MHPMCOUNTEND-`MHPMCOUNTSTART+1];
+       Reg#(Bit#(`Reg_width)) csr_mhpmevent[`MHPMCOUNTEND-`MHPMCOUNTSTART+1];
+       for(Integer i=0;i<=(`MHPMCOUNTEND-`MHPMCOUNTSTART);i=i+1)begin
+               csr_mhpmcounter[i]<-mkCReg(2,0);
+       end
+       csr_mhpmevent[0]<-mkReg('h20000000);
+       csr_mhpmevent[1]<-mkReg('h20000);
+       csr_mhpmevent[2]<-mkReg('h4000);
+       `endif
+
+  //////////////////////////////////////////////////////////////////////////////////////////
+       ///////////////////////////////////////// Debug Registers /////////////////////////////////
+       `ifdef Debug
+               `ifdef Openocd
+                       Reg#(Bool) resetmode[2]<-mkCReg(2,False); // TODO
+                       Reg#(Bit#(1)) ebreakm<-mkReg(1);
+                       Reg#(Bit#(1)) ebreaks<-mkReg(1);
+                       Reg#(Bit#(1)) ebreaku<-mkReg(1);
+               `else
+                       Reg#(Bool) resetmode[2]<-mkCReg(2,False); // TODO
+                       Reg#(Bit#(1)) ebreakm<-mkReg(0);
+                       Reg#(Bit#(1)) ebreaks<-mkReg(0);
+                       Reg#(Bit#(1)) ebreaku<-mkReg(0);
+               `endif
+               Reg#(Bit#(1)) stopcount<-mkReg(0);
+               Reg#(Bit#(1)) stoptime <-mkReg(0);
+               Reg#(Bit#(3)) debugcause<-mkReg(0);
+               Reg#(Bit#(1)) step<-mkReg(0);
+               Reg#(Bit#(2)) debugprv<-mkReg(0);
+               Reg#(Bit#(32)) dcsr=concatReg13(readOnlyReg(4'd4), readOnlyReg(12'd0),
+               ebreakm,readOnlyReg(1'b0),ebreaks,ebreaku,
+               readOnlyReg(1'b0),
+               stopcount,stoptime,
+               readOnlyReg(debugcause),readOnlyReg(3'd0),
+               step,debugprv);
+               Reg#(Bit#(`VADDR)) dpc <-mkReg(0);
+               Reg#(Bit#(`Reg_width)) csr_dpc=concatReg2(readOnlyReg('d0),dpc);
+               Reg#(Bit#(`Reg_width)) dscratch0<-mkReg(0);
+               Reg#(Bool) debugmode_active[2]<-mkCReg(2,False);
+               Reg#(Bit#(`Reg_width)) debugentry<-mkReg(`DebugBase);
+               //////////////////////////////////////////////////////////////////////////////////////////
+               //////////////////////// Trigger Registers ////////////////////////////////////////
+               Reg#(Bit#(`Reg_width)) tselect=readOnlyReg('d0);
+               Reg#(Bit#(4)) trigger_type=readOnlyReg('d2); 
+               Reg#(Bit#(1)) dmode=readOnlyReg(1'd0);
+               Reg#(Bit#(6)) maskmax=readOnlyReg(6'd0);
+               Reg#(Bit#(1)) select<-mkReg(0);
+               Reg#(Bit#(1)) timing=readOnlyReg(1'b0);
+               Reg#(Bit#(6)) triggeraction=readOnlyReg(6'd0); // always enter debug mode.
+               Reg#(Bit#(1)) chain<-mkReg(0);
+               Reg#(Bit#(4)) triggermatch<-mkReg(0);
+               Reg#(Bit#(1)) triggerm<-mkReg(0);
+               Reg#(Bit#(1)) triggers<-mkReg(0);
+               Reg#(Bit#(1)) triggeru<-mkReg(0);
+               Reg#(Bit#(1)) execute<-mkReg(0);
+               Reg#(Bit#(1)) store<-mkReg(0);
+               Reg#(Bit#(1)) load<-mkReg(0);
+               Reg#(Bit#(`Reg_width)) tdata1=concatReg16(trigger_type,dmode,maskmax,
+               readOnlyReg(33'd0),select,timing,
+               triggeraction,chain,triggermatch,
+               triggerm,readOnlyReg(1'b0),triggers,triggeru,
+               execute,store,load);
+               Reg#(Bit#(`Reg_width)) tdata2<-mkReg(0);
+               Wire#(TriggerData) executetrigger<-mkDWire(TriggerData{ttype:tagged None,matchscheme:0});
+               Wire#(TriggerData) loadtrigger<-mkDWire(TriggerData{ttype:tagged None,matchscheme:0});
+               Wire#(TriggerData) storetrigger<-mkDWire(TriggerData{ttype:tagged None,matchscheme:0});
+               Reg#(Bool) rg_step_now<-mkReg(False);
+               rule generate_trigger_info_decode;
+                       if(execute==1 && ((rg_prv==User &&triggeru==1)||(rg_prv==Supervisor &&triggers==1)||(rg_prv==Machine &&triggerm==1)) )
+                               executetrigger<=TriggerData{ttype:select==0?tagged Address tdata2:tagged Data tdata2,matchscheme:triggermatch};
+                       if(load==1&& ((rg_prv==User &&triggeru==1)||(rg_prv==Supervisor &&triggers==1)||(rg_prv==Machine &&triggerm==1)) )
+                               loadtrigger<=TriggerData{ttype:select==0?tagged Address tdata2:tagged Data tdata2,matchscheme:triggermatch};
+                       if(store==1&& ((rg_prv==User &&triggeru==1)||(rg_prv==Supervisor &&triggers==1)||(rg_prv==Machine &&triggerm==1)) )
+                               storetrigger<=TriggerData{ttype:select==0?tagged Address tdata2:tagged Data tdata2,matchscheme:triggermatch};
+               endrule
+       `endif
+`ifdef Debug
+       function Bool checktrigger(TriggerData tdata, Bit#(`VADDR) pc1, Bit#(32) instruction);
+                       Bit#(`Reg_width) pc=zeroExtend(pc1);
+                       if(tdata.ttype matches tagged Address .addr)
+                               if(tdata.matchscheme==0 && addr==pc)
+                                       return True;
+                               else if(tdata.matchscheme==2 && addr>=pc)
+                                       return True;
+                               else if(tdata.matchscheme==3 && addr<=pc)
+                                       return True;
+                               else if(tdata.matchscheme==4 && addr[31:0]==(addr[63:32]&pc[31:0]))
+                                       return True;
+                               else if(tdata.matchscheme==5 && addr[31:0]==(addr[`Reg_width-1:32]&pc[`Reg_width-1:32]))
+                                       return True;
+                               else
+                                       return False;
+                       else if(tdata.ttype matches tagged Data .data)
+                               if(data[31:0]==instruction)
+                                       return True;
+                               else
+                                       return False;
+                       else 
+                               return False;
+               endfunction
+`endif
+/////////// Functions to access CSRs /////////////////////////////////////////////////////////////
+       function Reg#(Bit#(`Reg_width)) read_user_sro_registers(Bit#(8) addr);
+               Reg#(Bit#(`Reg_width)) csr=(case(addr)
+                       `UCYCLE                         :csr_ucycle;                            
+                       `UTIME                          :readOnlyReg(rg_clint_mtime);  
+                       `UINSTRET                       :csr_uinstret;
+                       `ifndef RV64 
+                               `UCYCLEH                        :csr_ucycleh; 
+                               `UINSTRETH              :csr_uinstreth; 
+                       `endif
+                       default:readOnlyReg(0);
+                       endcase);
+               return csr;
+       endfunction
+       function Reg#(Bit#(`Reg_width)) read_user_srw_registers(Bit#(8) addr);
+               Reg#(Bit#(`Reg_width)) csr=(case(addr)
+                       `FFLAGS  :csr_fflags    ;
+                       `FRM             :csr_frm       ;
+                       `FCSR            :csr_fcsr      ;
+                       `UMEMSE  :csr_memse;
+                       default: readOnlyReg(0);
+               endcase);
+               return csr;
+       endfunction
+       `ifdef MMU
+       function Reg#(Bit#(`Reg_width)) read_supervisor_srw_registers(Bit#(8) addr);
+               Reg#(Bit#(`Reg_width)) csr=(case(addr)
+                       `SSTATUS    :csr_sstatus; 
+                       `SEDELEG    :csr_sedeleg; 
+                       `SIDELEG    :csr_sideleg; 
+                       `SIE        :csr_sie; 
+                       `STVEC      :csr_stvec; 
+                       `SCOUNTEREN :csr_scounteren; 
+                       `SSCRATCH   :csr_sscratch; 
+                       `SEPC       :csr_sepc; 
+                       `SCAUSE     :csr_scause; 
+                       `STVAL      :csr_stval; 
+                       `SIP        :csr_sip; 
+                       `SATP       :csr_satp;
+                       default:readOnlyReg(0);
+                       endcase);
+               return csr;
+       endfunction
+       `endif
+       function Reg#(Bit#(`Reg_width)) read_machine_srw_registers(Bit#(8) address);
+               Reg#(Bit#(`Reg_width)) csr=(case(address)
+                       `MSTATUS                        :csr_mstatus;           
+                       `MISA                           :csr_misa;
+                       `MEDELEG                        :csr_medeleg;
+                       `MIDELEG                        :csr_mideleg;
+                       `MIE                            :csr_mie;
+                       `MTVEC                  :csr_mtvec;
+                       `MCOUNTEREN             :csr_mcounteren;
+                       `MSCRATCH               :csr_mscratch;
+                       `MEPC                           :csr_mepc;
+                       `MCAUSE                 :((rg_mxl==1)?concatReg3(readOnlyReg(32'd0), rg_interrupt, rg_lower_cause):csr_mcause);
+                       `MTVAL                  :csr_mtval;
+                       `MIP                            :csr_mip;
+                       `MPOWERCONTROL  :csr_power_control;
+                       `PMPCFG0                :csr_pmpcfg0;
+               `ifndef RV64
+                       `PMPCFG1                :csr_pmpcfg1;
+               `endif
+                       `PMPCFG2                :csr_pmpcfg2;
+               `ifndef RV64
+                       `PMPCFG3                :csr_pmpcfg3;
+               `endif
+                       default: begin
+                       `ifdef perf
+                               if(address>=`PMPADDRSTART && address<=`PMPADDREND) // lower 4 bits of the counter
+                                       csr_pmpaddr[address[3:0]];
+                               else if(address>=`MHPMEVENTSTART && address<=`MHPMEVENTEND) // lower 32 bits of the counter
+                                       csr_mhpmcounter[(address-3)[1:0]][1];
+                               else 
+                       `endif
+                                       readOnlyReg(0);
+                       end
+                       endcase);
+               return csr;
+       endfunction
+       function Reg#(Bit#(`Reg_width))read_machine_sro_registers(Bit#(8) address);
+               Reg#(Bit#(`Reg_width)) csr=(case(address)
+                       `MVENDORID:csr_mvendorid;       
+                       `MARCHID         :csr_marchid;
+                       `MIMPID  :csr_mimpid;
+                       `MHARTID         :csr_mhartid;
+                       `MBOOTSEQ : csr_boot_seq;
+                       default:readOnlyReg(0);
+                       endcase);
+               return csr;
+       endfunction
+
+       function Reg#(Bit#(`Reg_width)) read_machine_counters(Bit#(8) address);
+               Reg#(Bit#(`Reg_width)) csr=(case(address)
+                       `MCYCLE                 :csr_mcycle[1];                         
+                       `MINSTRET               :csr_minstret[1];
+                       `ifndef RV64
+                               `MCYCLEH                :csr_mcycleh[1];
+                               `MINSTRETH      :csr_minstreth[1];
+                       `endif
+                       default: begin
+                       `ifdef perf
+                               if(address>=`MHPMCOUNTSTART && address<=`MHPMCOUNTEND) // lower 32 bits of the counter
+                                       csr_mhpmcounter[(address-3)[1:0]][1];
+                               else 
+                       `endif
+                                       readOnlyReg(0);
+                       end
+                       endcase);
+               return csr;
+       endfunction
+`ifdef Debug
+       function Reg#(Bit#(`Reg_width)) read_debug_registers(Bit#(8) address);
+               Reg#(Bit#(`Reg_width)) csr=(case(address)
+                       `DCSR: concatReg2(readOnlyReg(32'd0),dcsr);
+                       `DPC:    csr_dpc;
+                       `DSCRATCH0: dscratch0;
+                       `DENTRY  : debugentry;
+                       `TSELECT         : tselect;
+                       `TDATA1  : tdata1;
+                       `TDATA2  : tdata2;
+                       default:readOnlyReg(0); 
+               endcase);
+               return csr;
+       endfunction
+`endif
+  function Reg#(Bit#(`Reg_width)) read_csr(Bit#(12) addr);
+   Reg#(Bit#(`Reg_width)) csr=(
+    case(addr[11:8])
+               'h0: read_user_srw_registers(truncate(addr)); // user standard read-write
+               'hC: read_user_sro_registers(truncate(addr)); // user standard read-only
+               `ifdef MMU 'h1: read_supervisor_srw_registers(truncate(addr)); `endif // supervisor read-write 
+               'h3: read_machine_srw_registers(truncate(addr)); // machine standard read-write
+               'hF: read_machine_sro_registers(truncate(addr)); // machine standard read-only
+               'hB: read_machine_counters(truncate(addr)); // machine standard counters
+               `ifdef Debug 'h7: read_debug_registers(truncate(addr)); `endif
+      default: readOnlyReg(0);//read_perfcounter(address);
+    endcase
+    ); 
+    return csr;
+  endfunction
+       
+  function Bool hasCSRPermission(Bit#(12) address, Bool write);
+    Bit#(12) csr_index = pack(address);
+               Bool check_counter_permission = True;
+               if(address >= 12'hB00 && address <= 12'hB1F) begin
+                       check_counter_permission = False;
+                       if(pack(rg_prv) == 3) 
+                               check_counter_permission = True;
+                       else if(pack(rg_prv) == 1 && csr_mcounteren[address[4:0]]==1)
+                               check_counter_permission = True;
+                       `ifdef MMU
+                       else if(pack(rg_prv) == 0 && csr_scounteren[address[4:0]]==1)
+                               check_counter_permission = True;
+                       `endif
+               end
+    return ((pack(rg_prv) >= csr_index[9:8]) && check_counter_permission && !(write && csr_index[11:10]==2'b11) );//(!write || (csr_index[11:10] != 2'b11))) || check_counter_permission);
+  endfunction
+   
+  // if the operand is not 0 then the instruction will perform a write on the CSR.
+       function Bool valid_csr_access(Bit#(12) csr_addr, Bit#(5) operand, Bit#(2) operation);
+               Bool ret = hasCSRPermission(unpack(csr_addr), (operand != 0 || operation=='b01) ? True:False);
+               return ret;
+       endfunction
+
+       function Bool address_valid(Bit#(12) csr_address);
+               case(csr_address[11:8])
+                       'h0: begin
+                               if((csr_address[7:0]>'h5 && csr_address[7:0]<'h40) ||
+                                (csr_address[7:0]>'h44))
+                                       return False;
+                               else
+                                       return True;
+                       end
+                       'h1:begin
+                               if((csr_address[7:0]==1)||
+                                (csr_address[7:0]>'h6 && csr_address[7:0]<'h40) ||
+                                (csr_address[7:0]>'h44 && csr_address[7:0]!='h80))
+                                       return False;
+                               else 
+                                       return True;
+                       end
+                       'h3: begin // machine read-write registers
+                               if((csr_address[7:0]>'h6 && csr_address[7:0]<'h23) || 
+                                 (csr_address[7:0]>'h26 && csr_address[7:0]<'h40) ||
+                                 (csr_address[7:0]>'h44 && csr_address[7:0]<='hA0) ||
+                                 (csr_address[7:0]>'hA3 && csr_address[7:0]<'hB8) ||
+                                 (csr_address[7:0]>'hbf))
+                                       return False;
+                               else
+                                       return True;
+                       end
+                       'h7: begin
+                               if((csr_address[7:0]<'hA0)||
+                                (csr_address[7:0]>'hA3 && csr_address[7:0]<'hB0)||
+                                (csr_address[7:0]>'hB2)) 
+                                       return False; 
+                               else
+                                       return True;
+                       end
+                       'hB:begin
+                               if((csr_address[7:0]>'h6 && csr_address[7:0]<'h80 && csr_address[7:0]!='h20)||
+                                (csr_address[7:0]>'h86 && csr_address[7:0]<'hA0)||
+                                (csr_address[7:0]>'hA6))
+                                       return False;
+                               else
+                                       return True;
+                       end
+                       'hC:begin
+                               if((csr_address[7:0]>'h6 && csr_address[7:0]<'h83)|| 
+                                (csr_address[7:0]>'h86))
+                                       return False; 
+                               else
+                                       return True;
+                       end
+                       'hF:begin
+                               if(csr_address[7:0]<'h11 || csr_address[7:0]>'h15)
+                                       return False;
+                               else
+                                       return True;
+                       end
+                       default:return False;
+               endcase
+       endfunction
+
+  rule increment_cycle_counter `ifdef Debug (stopcount==0) `endif ;
+               `ifdef RV64
+       csr_mcycle[0]<=csr_mcycle[0]+1;
+               `else
+                       Bit#(64) new_cycle={csr_mcycleh[0],csr_mcycle[0]);
+                       new_cycle=new_cycle+1;
+                       csr_mcycle[0]<=new_cycle[31:0];
+                       csr_mcycleh[0]<=new_cycle[63:32];
+               `endif
+  endrule
+       
+
+       // Check pending interrupts
+       function ActionValue#(Trap_type) fn_chk_pending_interrupt(`ifdef Debug Bool haltreq, Bool resumereq , Bool resetreq`endif )=
+       actionvalue
+               `ifdef Debug
+                       Bit#(15) pending_debug_interrupt=0;
+                       if(haltreq && !debugmode_active[0] && !resetmode[0]) 
+                               pending_debug_interrupt[12]=1;  
+                       if(resumereq && debugmode_active[0] && !resetmode[0])
+                               pending_debug_interrupt[13]=1;
+                       if(resetreq && !resetmode[0] && debugmode_active[0])
+                               pending_debug_interrupt[14]=1;
+               `endif
+               Bit#(`Reg_width) lv_csr_mip = csr_mip;
+               lv_csr_mip[11]=lv_csr_mip[11]|pack(rg_nmi);
+               Bit#(15) pending_interrupts = (truncate(csr_mip)`ifdef Debug |pending_debug_interrupt `endif ) & truncate(csr_mie) ;
+        `ifdef verbose $display("Pending_interrupts in the beginning csr_mip : %b pending_interrupt: %b", csr_mip, pending_interrupts); `endif
+        // machine mode
+               let pending_machine_interrupts = pending_interrupts & ~truncate(csr_mideleg);
+               let machine_interrupts_enabled = (rg_mie == 1) || (pack(rg_prv) < pack(Machine));
+               //supervisor mode
+               `ifdef MMU
+               let pending_supervisor_interrupts = pending_interrupts & truncate(csr_mideleg) & ~truncate(csr_sideleg);
+               let supervisor_interrupts_enabled = (rg_sie == 1) && (pack(rg_prv) <= pack(Supervisor));
+               `endif
+               // user mode
+               // combined
+               pending_interrupts =    (machine_interrupts_enabled ? pending_machine_interrupts : 0)
+                                                                               `ifdef MMU      |(supervisor_interrupts_enabled ? pending_supervisor_interrupts : 0) `endif ;
+                                                                               
+               // format pendingInterrupt value to return
+               Trap_type ret = tagged None;
+               if (pending_interrupts != 0) begin
+                       ret = tagged Interrupt unpack(zeroExtend(pack(countZerosLSB(pending_interrupts))));
+               end
+               `ifdef verbose $display("Debug interrupts: %h pending_interrupt: %h csr_mie: %h rg_mie: %b ret: ",`ifdef Debug pending_debug_interrupt `else 0 `endif ,pending_interrupts,csr_mie,rg_mie,fshow(ret)); `endif
+               return ret;
+       endactionvalue;
+
+       
+       method ActionValue#(Tuple2#(Bit#(3),Trap_type)) check_for_trap(`ifdef Debug Bool haltreq, Bool resumereq, Bool resetreq, `endif Bit#(`VADDR) pc, Bit#(32) instruction)if(!rg_initialize[1] `ifdef simulate && !wr_endsimulation `endif ); 
+               Trap_type trap_type=tagged None;
+               Bit#(3) lv_debugcause=0;
+               let opcode=instruction[6:2];
+               if(opcode==`CSR_op)begin
+                       case(instruction[14:12])
+                               'd0:case (instruction[31:20])
+                                       'h000: // ECALL
+                                               trap_type=tagged Exception(case(rg_prv) User: Ecall_from_user; Supervisor:Ecall_from_supervisor;Machine:Ecall_from_machine;endcase); 
+                                               'h001:begin // EBREAK
+                                               `ifdef Debug
+                                                       Bit#(4) ebreak={ebreakm,0,ebreaks,ebreaku};
+                                                       if((ebreak)[pack(rg_prv)]==1)
+                                                               trap_type=tagged Interrupt DebugInterrupt;
+                                                       else
+                                               `endif
+                                                               trap_type=tagged Exception Breakpoint;
+                                                       lv_debugcause=1;
+                                               end
+                                       'h102:begin // SRET
+                                               if(pack(rg_prv)<pack(Supervisor)) trap_type=tagged Exception Illegal_inst;
+                                       end
+                                       'h302:begin // MRET
+                                               if(pack(rg_prv)<pack(Machine)) trap_type= tagged Exception Illegal_inst;
+                                       end
+                                       endcase
+                               default: begin
+                                       Bool address_is_valid=address_valid(instruction[31:20]);
+                                       Bool access_is_valid=valid_csr_access(instruction[31:20],instruction[19:15], instruction[13:12]);
+                                       `ifdef verbose $display($time,"\tCSR: Address: %h AddressValid: %b AccessValid: %b",instruction[31:20],address_is_valid,access_is_valid); `endif
+                                       if(!(address_is_valid && access_is_valid)) 
+                                               trap_type=tagged Exception Illegal_inst;
+                               end
+                       endcase
+               end
+               if(opcode==`FMADD_op || opcode==`FNMSUB_op || opcode==`FNMADD_op || opcode==`FMSUB_op || opcode==`FLOAT_op)begin
+                       if(instruction[14:12]=='b111 && rg_frm>4)
+                               trap_type=tagged Exception Illegal_inst;
+               end
+               if((opcode[4:3]=='b10 || opcode==`FSTORE_op || opcode==`FLOAD_op) && rg_fs==0)
+                       trap_type=tagged Exception Illegal_inst;
+               `ifdef Debug
+                       if(checktrigger(executetrigger,pc,instruction))begin
+                               `ifdef verbose $display("TRAP: Trigger Fired Debug Interupt"); `endif
+                               trap_type=tagged Exception Breakpoint;
+                               lv_debugcause=2;
+                       end
+               `endif
+               let pending_interrupt <- fn_chk_pending_interrupt(`ifdef Debug haltreq,resumereq, resetreq `endif );// TODO but resume request here
+               if(pending_interrupt matches tagged Interrupt .interrupt) begin
+                       `ifdef verbose $display($time,"\tinterrupt injected in to pipeline"); `endif
+                       trap_type=tagged Interrupt interrupt;
+                       `ifdef Debug 
+                               if(interrupt ==DebugInterrupt)
+                                       lv_debugcause=(step==1)?4:3;
+                       `endif
+       end
+               return tuple2(lv_debugcause,trap_type);
+       endmethod
+
+       method ActionValue#(Tuple4#(Bool,Bit#(`VADDR),Bit#(`Reg_width),Bool)) system_instruction(WriteBackType wbdata ,Bit#(`VADDR) pc, Bit#(`PERFMONITORS) perfmonitor_incr  `ifdef simulate , Bit#(32) instruction, Operand_type rd_type, Bit#(5) destination `endif )if(!rg_initialize[1] `ifdef simulate && !wr_endsimulation `endif );
+               Bool flush=True; // TODO flush for only writting on certain csr registers
+               Bool commit=False;
+               Bit#(`VADDR) jump_address=pc+4;
+               Bit#(`Reg_width) destination_value=0;
+               /*====== Execute the current instruction and generate a halt interrupt on the next ===== */
+               `ifdef Debug
+               `ifdef verbose $display($time,"CSR: STEP_NOW : %b",rg_step_now); `endif
+               if(step==1 && !debugmode_active[0] && !rg_step_now)
+                       rg_step_now<=True;
+               else 
+                       rg_step_now<=False;
+               `endif
+               /*======================================================================================= */
+               if(wbdata matches tagged SYSTEM .csr)begin
+                       let csr_reg=read_csr(csr.csr_address);
+                       if(csr.funct3==0)begin
+                               case (csr.csr_address[11:8]) matches
+                                       'h3:begin  // MRET
+                                               Privilege_mode next_prv =unpack(rg_mpp);
+                         rg_mpie <= 1;
+                         rg_mpp <= pack(User);
+                         rg_prv <= next_prv;
+                         jump_address=truncate(csr_mepc);
+                                                rg_mie<=rg_mpie;
+                                       end
+                                       `ifdef MMU
+                                               'h1:begin  // SRET
+                                                       if(csr.csr_address[5]==0)begin
+                                   Privilege_mode next_prv =unpack({1'b0,rg_spp});
+                                           rg_spie <= 1;
+                                           rg_spp <= pack(User)[0];
+                                                   rg_prv <= next_prv;
+                                                           jump_address=truncate(csr_sepc);
+                                                                rg_sie<=rg_spie;
+                                                       end
+                                                       else begin // SFENCE
+                                                               jump_address=pc+4;
+                                                               `ifdef simulate
+                                                                       Bit#(64) pc1=signExtend(pc[38:0]);
+                                                                       $fwrite(dump, rg_prv," 0x%16h",pc1, " (0x%8h", instruction,")" ); 
+                                                                       $fwrite(dump," x%d",destination," 0x%16h",destination_value,"\n"); 
+                                                               `endif
+                                                               `ifdef Debug 
+                                                                       if(resetmode[0])
+                                                                               resetmode[0]<=False;
+                                                               `endif
+                                                       end
+                       end
+                                       `endif
+                                       `ifdef Debug
+                                               'h7:begin // DRET
+                                                       jump_address=dpc;
+                                                       rg_prv<=unpack(debugprv);
+                                                       debugmode_active[0]<=False;
+                                               end
+                                       `endif
+                               endcase
+                               `ifdef Debug 
+                                       if(stopcount==0 && !debugmode_active[0]) begin
+                                               csr_minstret[0]<=csr_minstret[0]+1;
+                                       end
+                               `endif
+                               for(Integer i=0;i<=(`MHPMCOUNTEND-`MHPMCOUNTSTART);i=i+1)
+                                       if((csr_mhpmevent[i]&perfmonitor_incr)!=0 `ifdef Debug && stopcount==0 `endif )
+                                               csr_mhpmcounter[i][1]<=csr_mhpmcounter[i][1]+1;
+                               `ifdef verbose 
+                               for(Integer i=0;i<=(`MHPMCOUNTEND-`MHPMCOUNTSTART);i=i+1)begin
+                                       $display($time,"\tEVENT: :%h %s",csr_mhpmevent[i],event_name(csr_mhpmevent[i])," : %d",csr_mhpmcounter[i][1]);
+                               end
+                               `endif
+                       end
+                       else begin
+                  destination_value=csr_reg; 
+                               `ifdef verbose $display($time,"\tCSR: Dest: %h Value: %h rs1: %h funct3: %d rs1_addr: %d",csr.csr_address,csr_reg,csr.rs1,csr.funct3,csr.rs1_addr); `endif
+                               commit=True;
+                  case(csr.funct3)
+                                       'd1: csr_reg <= csr.rs1;                                        // CSRRW
+                       'd2:if(csr.rs1_addr!=0)  csr_reg <= csr.rs1 | csr_reg;                  // CSRRS 
+                       'd3:if(csr.rs1_addr!=0)  csr_reg <= ~(csr.rs1) & csr_reg;    // CSRRC 
+                       'd5: csr_reg <= zeroExtend(csr.rs1_addr);                               // CSRRWI 
+                       'd6:if(csr.rs1_addr!=0)  csr_reg <= zeroExtend(csr.rs1_addr) | csr_reg;         // CSRRSI 
+                       'd7:if(csr.rs1_addr!=0)  csr_reg <= ~(zeroExtend(csr.rs1_addr)) & csr_reg; //CSRRCI 
+                  endcase
+                               `ifdef simulate
+                                       Bit#(64) pc1=signExtend(pc[38:0]);
+                                       $fwrite(dump, rg_prv," 0x%16h",pc1, " (0x%8h", instruction,")" ); 
+                                       $fwrite(dump," x%d",destination," 0x%16h",destination_value); 
+                                       $fwrite(dump,"\n");
+                               `endif
+               end
+               end
+               else if(wbdata matches tagged RESULT .res)begin
+                       for(Integer i=0;i<=(`MHPMCOUNTEND-`MHPMCOUNTSTART);i=i+1)
+                               if((csr_mhpmevent[i]&perfmonitor_incr)!=0 `ifdef Debug && stopcount==0 `endif )
+                                       csr_mhpmcounter[i][1]<=csr_mhpmcounter[i][1]+1;
+                               `ifdef verbose 
+                               for(Integer i=0;i<=(`MHPMCOUNTEND-`MHPMCOUNTSTART);i=i+1)begin
+                                       $display($time,"\tEVENT: :%h %s",csr_mhpmevent[i],event_name(csr_mhpmevent[i])," : %d",csr_mhpmcounter[i][1]);
+                               end
+                               `endif
+                       `ifdef simulate
+                               Bit#(64) pc1=signExtend(pc[38:0]);
+                               $fwrite(dump, rg_prv," 0x%16h",pc1, " (0x%8h", instruction,")" ); 
+                       `endif
+                       commit=True;
+                       `ifdef Debug 
+                               if(stopcount==0 && !debugmode_active[0])begin
+                                       csr_minstret[0]<=csr_minstret[0]+1;
+                               end
+                       `endif
+                       flush=False;
+                       destination_value=res.aluresult;
+                       let newfflags=res.fflags;
+                       let fpudirty=False;
+                       if((newfflags|rg_fflags)!=rg_fflags)begin
+                               rg_fflags<=newfflags|rg_fflags;
+                               fpudirty=True;
+                       end
+                       if(fpudirty)
+                               if(rg_fs==2'b0)begin
+                                       `ifdef verbose $display("Error: FPU id Dirty and FX field is 0"); `endif
+                               end
+                       `ifdef simulate
+                               Bit#(64) dat=signExtend(res.aluresult);
+                               `ifdef spfpu
+                                       if(rd_type==FloatingRF)
+                                               `ifdef dpfpu
+                                                       $fwrite(dump," f%d",destination," 0x%16h",dat); 
+                                               `else
+                                                       $fwrite(dump," f%d",destination," 0x%16h",{32'hffffffff,dat[31:0]}); 
+                                               `endif
+                                       else
+                               `endif
+                                       $fwrite(dump," x%d",destination," 0x%16h",dat); 
+                               $fwrite(dump,"\n");
+                       `endif
+               end
+               return tuple4(flush,jump_address,destination_value, commit);
+       endmethod
+
+       method ActionValue#(Tuple2#(Bit#(`VADDR), Bool)) take_trap(Trap_type exception, Bit#(3) lv_debugcause, Bit#(`VADDR) pc, Bit#(`VADDR) badaddr)if(!rg_initialize[1]);
+               Bit#(`VADDR) jump_address=0;
+               Bool flush=True;
+               if(exception matches tagged Exception .ex)begin
+                       if(ex==Inst_addr_misaligned || ex==Inst_access_fault || ex==Inst_pagefault)
+                               badaddr=pc;
+                       else if(ex==Illegal_inst)
+                               badaddr=0;
+      else if(ex!=Load_pagefault && ex!=Load_access_fault && ex!=Load_addr_misaligned && ex!=Store_addr_misaligned && ex!=Store_pagefault && ex!=Store_access_fault)
+        badaddr=0;
+               end
+    else
+      badaddr=0;
+               `ifdef verbose $display($time,"\tTrap Type: ",fshow(exception)," debugcause: %d",lv_debugcause," BaddAddr: %h",badaddr);  `endif
+               `ifdef Debug
+               if(exception matches tagged Interrupt .in &&& in==DebugResume)begin
+                       if(debugmode_active[0])begin
+                               rg_prv<=unpack(debugprv);
+                               debugmode_active[0]<=False;
+                               jump_address=truncate(dpc);
+                       end
+               end
+               else if(exception matches tagged Interrupt .in &&& in==DebugInterrupt)begin
+                       debugmode_active[0]<=True;
+                       if(!debugmode_active[0])begin
+                               dpc<=pc;
+                               debugcause<=lv_debugcause;
+                               debugprv<=pack(rg_prv);
+                               rg_prv<=Machine;
+                               if(lv_debugcause==4)
+                                       rg_step_now<=False;
+                       end
+                       jump_address=truncate(debugentry);
+               end
+               else if(exception matches tagged Interrupt .in &&& in==DebugReset)begin
+                       resetmode[0]<=True;
+                       jump_address='h1000;
+                       rg_prv<=Machine;
+               end
+               else if(!debugmode_active[0] && !resetmode[0])begin
+               `endif
+                       Bit#(`Reg_width) cause = 0;
+                       Bit #(TSub #(`Reg_width, 1)) cause_code = 0;
+                       Bit #(1) cause_type = 0;
+                       case (exception) matches
+                               tagged Interrupt .i: begin cause_type = 1; cause_code = zeroExtend(pack(i)); end
+                               tagged Exception .e: begin cause_type = 0; cause_code = zeroExtend(pack(e)); 
+                                       `ifdef simulate if(e==Endsimulation) begin
+                                               for(Integer i=0;i<=(`MHPMCOUNTEND-`MHPMCOUNTSTART);i=i+1)begin
+                                                       $display($time,"\tEVENT: %s",event_name(csr_mhpmevent[i])," : %d",csr_mhpmcounter[i][1]);
+                                               end
+                                               $finish(0) /*wr_endsimulation <=True*/ ;  
+                                               end
+                                       `endif 
+                               end
+                       endcase
+                       cause = {cause_type, cause_code};
+                       `ifdef MMU
+                       Bool delegToS = (pack(rg_prv) <= pack(Supervisor)) && (case (exception) matches
+                               tagged Exception .exceptionCause:begin (((csr_medeleg >> pack(exceptionCause)) & 1) != 0);end
+             tagged Interrupt .interruptCause: (((csr_mideleg >> pack(interruptCause)) & 1) != 0);
+          endcase);
+                       if(delegToS)begin
+                               //if(exception matches tagged Exception .ex)
+                               //      if(ex==Inst_addr_misaligned || ex==Inst_access_fault || ex==Inst_pagefault || ex==Illegal_inst 
+                               //                                                                                      || ex==Load_access_fault || ex==Load_addr_misaligned || ex==Load_pagefault
+                               //                                                                                                                      || ex==Store_addr_misaligned || ex==Store_access_fault || ex==Store_pagefault)
+                               csr_stval<=zeroExtend(badaddr);
+                               csr_sepc<=signExtend(pc);
+                               csr_scause<=cause;
+                               rg_spp <= pack(rg_prv)[0];
+                               rg_sie <=0;
+                               rg_spie <= rg_sie;//(case (rg_prv)  User: rg_uie;  Supervisor : rg_sie;  endcase);
+                               jump_address=truncate(csr_stvec);
+                               rg_prv <= Supervisor;
+                       end
+                       else begin
+                       `endif
+                               rg_prv <= Machine;
+                               if(exception matches tagged Exception .ex)
+                                       if(ex==Inst_addr_misaligned || ex==Inst_access_fault || ex==Inst_pagefault || ex==Illegal_inst 
+                                                                                                                       || ex==Load_access_fault || ex==Load_addr_misaligned || ex==Load_pagefault
+                                                                                                                                                       || ex==Store_addr_misaligned || ex==Store_access_fault || ex==Store_pagefault)
+                               csr_mtval<=zeroExtend(badaddr);
+                               csr_mepc<=signExtend(pc);
+        if(rg_mxl==1)
+          csr_mcause<= zeroExtend({cause[63], cause[30:1]});
+        else
+                               csr_mcause<=cause;
+                               rg_mie <= 0;
+                               rg_mpp <= pack(rg_prv);
+                               jump_address=truncate(csr_mtvec);
+                               rg_mpie <= rg_mie;//(case (rg_prv)  User: rg_uie; `ifdef MMU Supervisor : rg_sie; `endif Machine: rg_mie;  endcase);
+                       `ifdef MMU
+                       end
+                       `endif
+
+               `ifdef Debug 
+                       end
+                       else begin
+                               flush=False;
+                       end
+               `endif
+               return tuple2(jump_address,flush);
+       endmethod
+       method Bit#(3) roundingmode if(!rg_initialize[1] `ifdef simulate && !wr_endsimulation `endif );
+               return rg_frm;
+       endmethod
+       method Action set_external_interrupt(Tuple2#(Bool,Bool) ex_i) if(!rg_initialize[1] `ifdef simulate && !wr_endsimulation `endif );
+               let {i,j} = ex_i;
+               rg_nmi <= j;
+               if(rg_prv == Machine) begin
+               `ifdef verbose $display("CSR : Machine external interrupt pending"); `endif
+                       rg_meip <= pack(i);
+               end
+               else if(rg_prv == Supervisor) begin
+                       rg_seipe <= pack(i);
+               end
+               else if(rg_prv == User) begin
+                       rg_ueipe <= pack(i);
+               end
+       endmethod
+       method Action flush;
+               rg_initialize[0]<=True;
+       endmethod
+       `ifdef MMU
+       method Bit#(`Reg_width) send_satp;
+               return csr_satp;
+       endmethod
+       method Chmod perm_to_TLB;
+               return Chmod {mprv : rg_mprv, sum : rg_sum, mxr : rg_mxr, mpp : unpack(rg_mpp), prv : rg_prv};
+       endmethod
+       `endif
+       method Bit#(`Reg_width) mmu_cache_disable;
+               return csr_memse;
+       endmethod
+       `ifdef Debug
+               method Bool halted;
+                       return debugmode_active[1];
+               endmethod
+               method load_triggerdata=loadtrigger;
+               method store_triggerdata=storetrigger;
+               method ActionValue#(Bit#(`Reg_width)) rw_debug_csr(Bit#(12) r, Bool write, Bit#(`Reg_width) data) if(!rg_initialize[1]);
+                       let y=read_csr(r);
+                       if(write)
+                               y<=data;
+                       return y._read;
+               endmethod
+               method Bool step_now=rg_step_now;
+               method Bool reset_mode=resetmode[1];
+       `endif
+       method Bit#(`Reg_width) misa=csr_misa._read;
+       method Action boot_sequence(Bit#(1) bootseq);
+               rg_boot_seq<=bootseq;
+       endmethod
+       method Bit#(2) powercontrol=power_control_out;
+       method Action poweracknowledge(Bit#(2) pa);
+               power_control_in<=pa;
+       endmethod
+       `ifdef CLINT
+               method Action clint_msip(Bit#(1) intrpt);
+                       rg_msip<=intrpt;
+               endmethod
+               method Action clint_mtip(Bit#(1) intrpt);
+                       rg_mtip<=intrpt;
+               endmethod
+               method Action clint_mtime(Bit#(`Reg_width) c_mtime);
+                       rg_clint_mtime<=c_mtime;
+               endmethod
+       `endif
+    method inferred_xlen=rg_mxl;
+
+  endmodule
+endpackage
+
diff --git a/src/core/dTLB.bsv b/src/core/dTLB.bsv
new file mode 100755 (executable)
index 0000000..bdd56fa
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+Copyright (c) 2013, IIT Madras
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+*  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+*  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+*  Neither the name of IIT Madras  nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+*/
+package dTLB;
+import defined_types::*;
+import FIFO::*;
+import SpecialFIFOs::*;
+import GetPut::*;
+import ConfigReg::*;
+
+`include "defined_parameters.bsv"
+
+`define TLB_entries    16      
+
+interface Ifc_TLB#(numeric type data_width, numeric type vaddr, numeric type paddr, numeric type page_size, numeric type asid_width);
+       method Action get_vaddr(DTLB_access#(data_width) addr `ifdef atomic , Bit#(5) atomic `endif );
+       method ActionValue#(From_TLB#(data_width)) send_ppn;
+       method ActionValue#(Bit#(vaddr)) send_vaddress_for_cache_index;
+       method Action translation_protection_frm_csr(bit tlb_disable, Chmod per_bits, Bit#(TAdd#(4,asid_width)) asid); //TODO parameterise this
+       interface Get#(Request_PPN_PTW#(vaddr,page_size)) to_PTW; 
+       interface Put#(Tuple2#(Bool,To_TLB#(paddr,page_size,asid_width))) refill_TLB;
+       method Action flush(Bool _flush);
+       method Action fence_TLB(Fence_VMA_type#(vaddr) rsdata);
+       //method ActionValue#(Bool) page_fault;
+       //method Action page_fault_frm_PTW;
+endinterface
+
+module mkTLB(Ifc_TLB#(data_width,vaddr,paddr,page_size,asid_width))
+provisos( Add#(vpn, page_size, vaddr),
+                                       Mul#(8, num_bytes, data_width),
+                                       Log#(num_bytes, byte_addressable_bits),
+                                       Add#(vpn_split,byte_addressable_bits, page_size),
+                                       Mul#(2,vpn_split,intermediate1),
+                                       Mul#(3,vpn_split,intermediate2),
+                                       Add#(a_, paddr, data_width),
+                                       Add#(b_, vaddr, data_width),
+                                       Add#(c_, vpn_split, vpn),
+                                       Add#(d_, intermediate1, vpn),
+                                       Add#(e_, intermediate2, vpn),
+                                       Add#(ppn, page_size, paddr));
+       
+       let v_vaddr = valueOf(vaddr);
+       let v_vpn = valueOf(vpn);
+       let v_ppn = valueOf(ppn);
+       let v_page_offset = valueOf(page_size);
+       let v_asid_width = valueOf(asid_width);
+       let v_vpn_split = valueOf(vpn_split);
+       let v_intermediate1 = valueOf(intermediate1);
+
+       Reg#(Bit#(vpn)) tlb_vpn[`TLB_entries];
+       Reg#(Bit#(ppn)) tlb_ppn[`TLB_entries];
+       Reg#(TLB_permissions) tlb_permissions[`TLB_entries];
+       Reg#(Bit#(asid_width)) tlb_asid[`TLB_entries];
+       Reg#(Bool)                              tlb_cacheable[`TLB_entries];
+       Reg#(Bit#(2)) tlb_levels[`TLB_entries];
+               for(Integer i = 0; i < `TLB_entries; i=i+1) begin
+                       tlb_vpn[i] <- mkReg(0);
+                       tlb_ppn[i] <- mkReg(0);
+                       tlb_permissions[i] <- mkReg(TLB_permissions{v:0,r:0,w:0,x:0,u:0,g:0,a:0,d:0});
+                       tlb_levels[i] <- mkReg(0);
+                       tlb_cacheable[i] <- mkReg(True);
+               end
+       FIFO#(Bit#(vpn)) ff_vpn <- mkBypassFIFO();
+       FIFO#(Bit#(page_size)) ff_page_offset <- mkBypassFIFO();
+       Reg#(Chmod) rg_chmod[2] <- mkCReg(2,Chmod { mprv : 0, mxr : 0, sum : 0, mpp : unpack(0), prv : unpack(0)});
+       Reg#(Bool) rg_page_fault[2] <- mkCReg(2,False);
+       Reg#(Bool) rg_hit[2] <- mkCReg(2,False);
+       Reg#(Bit#(2)) rg_levels[2] <- mkCReg(2,0);
+       Reg#(Bool) rg_handling_PTW[2] <- mkCReg(2,False);
+       Reg#(Bool) rg_tlb_disable <- mkConfigReg(False);
+       Reg#(Bool) rg_frm_ptw[2] <- mkCReg(2,False);
+       Reg#(Bit#(ppn)) rg_ppn[2] <- mkCReg(2,0);
+       Reg#(Bool) rg_cacheable[2] <- mkCReg(2,True);
+       Reg#(Bit#(asid_width)) rg_asid[2] <- mkCReg(2,0);
+       Reg#(Bit#(4)) rg_translation_mode[2] <- mkCReg(2,0);
+       FIFO#(Tuple2#(Access_type,Bit#(5))) ff_access <- mkBypassFIFO();
+       Reg#(Bit#(TLog#(`TLB_entries))) rg_slot_to_replace <- mkReg(0);
+       Wire#(Bool) wr_flush <- mkDWire(False);
+       
+       rule rl_translation(!rg_handling_PTW[0] && !rg_tlb_disable && (rg_chmod[1].prv!=Machine) && !rg_page_fault[0] 
+                                                                                                                                                                               && (rg_translation_mode[1]!=0) && !wr_flush && tpl_1(ff_access.first())!=Fence);
+               Bit#(ppn) ppn = 0;
+               TLB_permissions perm_bits = TLB_permissions{v:0,r:0,w:0,x:0,u:0,g:0,a:0,d:0};
+               Bool hit = False;
+               Bool page_fault = False;
+               Bool cacheable = False;
+               Bit#(vpn) vpn_bits = ff_vpn.first;
+               Bit#(vpn_split) lv_vpn_split= 0;
+               Bit#(intermediate1) lv_intermediate1 = 0;
+               Bit#(intermediate2) lv_intermediate2= 0;
+               Bit#(vpn) mask1 = {'1,lv_vpn_split};
+               Bit#(vpn) vpnmask1 = vpn_bits & mask1;
+               Bit#(vpn) mask2 = {'1,lv_intermediate1};
+               Bit#(vpn) vpnmask2 = vpn_bits & mask2;
+               Bit#(2) pg_levels = 0;
+               Integer slot = 0;
+               `ifdef verbose_torture $display($time, "\tThe acquired VPN in iTLB %h", ff_vpn.first); `endif
+               for(Integer i = 0; i < `TLB_entries; i = i + 1) begin
+                       if((vpn_bits==tlb_vpn[i] && tlb_levels[i]==0 
+                                               || ((vpnmask1==(tlb_vpn[i] & mask1)) && tlb_levels[i]==1)
+                                               || ((vpnmask2==(tlb_vpn[i] & mask2)) && tlb_levels[i]==2))
+                                               && (rg_asid[1]==tlb_asid[i] || tlb_permissions[i].g==1) && tlb_permissions[i].v==1) begin
+                       
+                                       `ifdef verbose_torture $display($time, "\t tlb_permissions valid ", fshow(tlb_permissions[i])); `endif
+                                       ppn = tlb_ppn[i];
+                                       perm_bits = tlb_permissions[i];
+                                       pg_levels = tlb_levels[i];
+                                       hit = True;
+                                       slot = i;
+                                       cacheable = tlb_cacheable[i];
+                       end
+               end
+               rg_levels[0] <= pg_levels;
+               if(hit) begin
+                       if(rg_chmod[1].sum==0) begin
+                               //if(rg_chmod[1].mprv==1) begin
+                               //      if(rg_chmod[1].mpp==unpack(1) && perm_bits.u==1) begin
+                               //              page_fault=True;
+                               //              $display($time, "\t dTLB: page fault 1");
+                               //      end
+                               //end
+                               if(rg_chmod[1].prv==unpack(1) && perm_bits.u==1) begin
+                                       page_fault=True;
+                                       `ifdef verbose_torture $display($time, "\t dTLB: page fault 2"); `endif
+                               end
+                       end
+                       if(tpl_1(ff_access.first())==Load `ifdef atomic || (tpl_1(ff_access.first)==Atomic && tpl_2(ff_access.first)[3:0]=='b0101) `endif ) begin
+                               if(rg_chmod[1].mxr==1) begin
+                                       if(perm_bits.x==0 || perm_bits.r==0) begin
+                                               page_fault=True;
+                                               `ifdef verbose_torture $display($time, "\t dTLB: page fault 3"); `endif
+                                       end
+                               end
+                               else begin
+                                       if(perm_bits.r==0) begin
+                                               page_fault=True;
+                                               `ifdef verbose_torture $display($time, "\t dTLB: page fault 4"); `endif
+                                       end
+                               end
+                       end
+                       else begin      
+                               if(perm_bits.w==0 || perm_bits.d==0) begin
+                                       page_fault=True;
+                                       `ifdef verbose_torture $display($time, "\t dTLB: page fault 5"); `endif
+       //                              if(perm_bits.d==0)
+       //                                      perm_bits.v = 0;
+       //                                      tlb_permissions[slot] <= perm_bits;
+                               end
+                       end
+                       rg_ppn[0] <= ppn;
+                       rg_cacheable[0] <= cacheable;
+                       `ifdef verbose_torture $display($time, "\t dTLB: hit"); `endif
+               end
+               else begin
+                       rg_handling_PTW[0] <= True;
+                       `ifdef verbose_torture $display($time, "\t dTLB: miss"); `endif
+               end
+               rg_page_fault[0]<=page_fault;
+               `ifdef verbose_torture $display($time, "\t dTLB: The page fault is  %b", page_fault); `endif
+               if(!page_fault) 
+                       rg_hit[0]<=hit;
+               else begin
+                       perm_bits.v = 0;
+                       tlb_permissions[slot] <= perm_bits;
+               end
+       endrule
+
+       rule rl_flush_TLB(wr_flush); 
+               ff_vpn.deq;
+               ff_page_offset.deq;
+               ff_access.deq;
+               rg_handling_PTW[1] <= False;
+               rg_hit[1] <= False;
+               rg_page_fault[1] <= False;
+               rg_frm_ptw[1] <= False;
+       endrule
+
+       method Action get_vaddr(DTLB_access#(data_width) addr `ifdef atomic , Bit#(5) atomic `endif );
+               `ifdef verbose_torture $display($time, "\t dTLB: Initiated translation through dTLB and disable is %b", rg_tlb_disable); `endif
+               ff_vpn.enq(addr.vaddr[v_vaddr-1: v_page_offset]);
+               ff_page_offset.enq(addr.vaddr[v_page_offset-1:0]);
+               ff_access.enq(tuple2(addr.ld_st_atomic, `ifdef atomic atomic `else 0 `endif ));
+       endmethod
+
+       method ActionValue#(From_TLB#(data_width)) send_ppn if(rg_hit[1] || rg_tlb_disable 
+                                                                                                                                                       || (rg_chmod[1].prv==Machine) || rg_page_fault[1] || (rg_translation_mode[1]==0) 
+                                                                                                                                                                                               || tpl_1(ff_access.first())==Fence);
+               Trap_type e = tagged None;
+               Bit#(data_width) final_address;
+               Bit#(ppn) p_ppn = 0;
+               if(rg_levels[1]==0) begin
+                       p_ppn = rg_ppn[1];
+               end
+               else if(rg_levels[1]==1) begin
+                       Bit#(TSub#(ppn,vpn_split)) lv_ppn_split = rg_ppn[1][v_ppn-1:v_vpn_split]; 
+                       Bit#(vpn_split) lv_vpn_split = ff_vpn.first[v_vpn_split-1:0];
+                       p_ppn = {lv_ppn_split,lv_vpn_split};
+               end
+               else if(rg_levels[1]==2) begin
+                       Bit#(TSub#(ppn,intermediate1)) lv_ppn_split = rg_ppn[1][v_ppn-1:v_intermediate1]; 
+                       Bit#(intermediate1) lv_vpn_split = ff_vpn.first[v_intermediate1-1:0];
+                       p_ppn = {lv_ppn_split,lv_vpn_split};
+               end
+               if(rg_hit[1]) begin
+                       rg_hit[1] <= False;
+                       Bit#(paddr) paddress = {p_ppn,ff_page_offset.first()};
+                       final_address = zeroExtend(paddress);
+                       rg_frm_ptw[0] <= False;
+               end
+               else if(rg_page_fault[1]) begin
+                       `ifdef verbose_torture $display($time, "\t DTLB Page Fault"); `endif
+                       if(tpl_1(ff_access.first())== Load `ifdef atomic || (tpl_1(ff_access.first)==Atomic && tpl_2(ff_access.first)[3:0]=='b0101) `endif ) 
+                               e = tagged Exception Load_pagefault;    
+                       else 
+                               e = tagged Exception Store_pagefault;   
+                       Bit#(vaddr) paddress = {ff_vpn.first(),ff_page_offset.first()};
+                       final_address = zeroExtend(paddress);
+                       rg_page_fault[1] <= False;
+                       rg_frm_ptw[0] <= False;
+               end
+               else begin
+                       `ifdef verbose_torture $display($time, "\t dTLB: Bypass"); `endif
+                       Bit#(vaddr) paddress = {ff_vpn.first(),ff_page_offset.first()};
+                       final_address = zeroExtend(paddress);
+               end
+               ff_page_offset.deq;
+               ff_vpn.deq;
+               ff_access.deq;
+               return From_TLB{exception : e, address : final_address, cacheable : rg_cacheable[1]};
+       endmethod
+
+       method ActionValue#(Bit#(vaddr)) send_vaddress_for_cache_index if(rg_frm_ptw[0]);
+               rg_frm_ptw[0] <= False;
+               return {ff_vpn.first, ff_page_offset.first};
+       endmethod
+
+       method Action translation_protection_frm_csr(bit tlb_disable, Chmod per_bits, Bit#(TAdd#(4,asid_width)) asid);
+               rg_tlb_disable <= unpack(tlb_disable);
+               rg_asid[0] <= asid[v_asid_width-1:0];
+               rg_translation_mode[0] <= asid[v_asid_width+3:v_asid_width];
+               per_bits.prv=per_bits.mprv==1?per_bits.mpp:per_bits.prv;
+               rg_chmod[0] <= per_bits;
+               `ifdef verbose_torture $display($time, "\t DTLB: mprv %b mxr %b sum %b mpp %b prv %b", per_bits.mprv, per_bits.mxr, per_bits.sum, pack(per_bits.mpp), pack(per_bits.prv)); `endif
+       endmethod
+               
+       interface to_PTW = interface Get
+               method ActionValue#(Request_PPN_PTW#(vaddr,page_size)) get if(rg_handling_PTW[1] && !rg_page_fault[1]); 
+                       return Request_PPN_PTW{ vpn : ff_vpn.first(), page_type : (tpl_1(ff_access.first())==Load `ifdef atomic || (tpl_1(ff_access.first)==Atomic && tpl_2(ff_access.first)[3:0]=='b0101) `endif )?Load:Store};
+               endmethod
+       endinterface;
+
+       interface refill_TLB = interface Put
+               method Action put(Tuple2#(Bool, To_TLB#(paddr,page_size,asid_width)) tlb_fill) if(rg_handling_PTW[0]);
+                       let {x,tlb_structure} = tlb_fill;
+                       rg_page_fault[1] <= x;
+                       Bit#(paddr) paddress= {tlb_structure.ppn,ff_page_offset.first};
+                       Bit#(data_width) new_address = zeroExtend(paddress);
+                       Bool cacheable = True; //!is_IO_Addr(zeroExtend(new_address)); TODO
+                       if(!x) begin
+                               rg_slot_to_replace <= rg_slot_to_replace + 1;
+                               tlb_vpn[rg_slot_to_replace] <= ff_vpn.first();
+                               tlb_ppn[rg_slot_to_replace] <= tlb_structure.ppn;
+                               tlb_permissions[rg_slot_to_replace] <= tlb_structure.tlb_perm;
+                               tlb_levels[rg_slot_to_replace] <= tlb_structure.levels;
+                               tlb_asid[rg_slot_to_replace] <= tlb_structure.asid;
+                               tlb_cacheable[rg_slot_to_replace] <= cacheable;
+                       end
+                       rg_handling_PTW[0] <= False;
+                       rg_frm_ptw[0] <= True;
+                       `ifdef verbose_torture $display($time, "\t Filling TLB in slot %d with vpn %h with page levels i %d", rg_slot_to_replace, ff_vpn.first(), tlb_structure.levels); `endif
+                       `ifdef verbose_torture $display($time, " dTLB: Filling TLB and page fault is %b", x);  `endif
+               endmethod
+       endinterface;
+
+       method Action flush(Bool _flush);
+               wr_flush <= _flush;
+       endmethod
+
+       method Action fence_TLB(Fence_VMA_type#(vaddr) rsdata);
+               Bool flush_address = False;
+               Bool flush_address_space = False;
+               Bit#(vpn_split) lv_vpn_split= 0;
+               Bit#(intermediate1) lv_intermediate1 = 0;
+               Bit#(intermediate2) lv_intermediate2= 0;
+               Bit#(vpn) mask1 = {'1,lv_vpn_split};
+               Bit#(vpn) vpnmask1 = rsdata.rs1[v_vaddr-1:v_page_offset] & mask1;
+               Bit#(vpn) mask2 = {'1,lv_intermediate1};
+               Bit#(vpn) vpnmask2 = rsdata.rs1[v_vaddr-1:v_page_offset] & mask2;
+               if(rsdata.rs1!=0) begin
+                       flush_address = True;
+                       `ifdef verbose_torture $display($time, "\t dTLB address flush %h", rsdata.rs1); `endif
+               end
+               if(rsdata.rs2!=0) begin
+                       flush_address_space = True;
+                       `ifdef verbose_torture $display($time, "\t dTLB address space flush %h", rsdata.rs2); `endif
+               end
+               for(Integer i = 0; i < `TLB_entries; i = i+1) begin
+                       if(((flush_address && ((rsdata.rs1[v_vaddr-1:v_page_offset] == tlb_vpn[i] && tlb_levels[i]==0)
+                                                       || (vpnmask1 == (tlb_vpn[i] & mask1) && tlb_levels[i]==1)
+                                                                       || (vpnmask2 == (tlb_vpn[i] & mask2) && tlb_levels[i]==2)))
+                                                                                       || (flush_address_space && rsdata.rs2[v_asid_width-1:0] == tlb_asid[i]))
+                                                                                                       || (!flush_address && !flush_address_space)) begin
+                               `ifdef verbose_torture $display($time, "\t dTLB entry %d with vpn %h removed",i, tlb_vpn[i]); `endif
+                               tlb_permissions[i] <= TLB_permissions{v : 0, r : 0, w : 0, x : 0, u : 0, g : 0, a : 0, d : 0};
+                       end
+               end
+       endmethod
+       
+       //method Action fence_TLB(Fence_VMA_type#(data_width) rsdata);
+       //      Bool flush_address = False;
+       //      Bool flush_address_space = False;
+       //      if(rsdata.rs1!=0) begin
+       //              flush_address = True;
+       //              `ifdef verbose_torture $display($time, "\t dTLB address flush %h", rsdata.rs1); `endif
+       //      end
+       //      if(rsdata.rs2!=0) begin
+       //              flush_address_space = True;
+       //              `ifdef verbose_torture $display($time, "\t dTLB address space flush %h", rsdata.rs2); `endif
+       //      end
+       //      for(Integer i = 0; i < `TLB_entries; i = i+1) begin
+       //              if(((flush_address && rsdata.rs1[v_vaddr-1:v_page_offset] == tlb_vpn[i])
+       //                                              || (flush_address_space && rsdata.rs2[v_asid_width-1:0] == tlb_asid[i]))
+       //                                                                      || (flush_address && flush_address_space)) begin
+       //              tlb_permissions[i] <= TLB_permissions{v : 0, r : 0, w : 0, x : 0, u : 0, g : 0, a : 0, d : 0};
+       //              end
+       //      end
+       //endmethod
+
+       //method ActionValue#(Bool) page_fault if(rg_page_fault[1]);
+       //      ff_vpn.deq;
+       //      ff_page_offset.deq;
+       //      ff_access.deq;
+       //      rg_hit[1] <= False;
+       //      return True;
+       //endmethod
+
+       //method Action page_fault_frm_PTW if(rg_handling_PTW[0]);
+       //      rg_page_fault[0] <= False;
+       //endmethod
+
+endmodule
+
+interface Ifc_dTLB;
+       method Action get_vaddr(DTLB_access#(`ADDR) addr `ifdef atomic , Bit#(5) atomic `endif );
+       method ActionValue#(From_TLB#(`ADDR)) send_ppn;
+       method ActionValue#(Bit#(`VADDR)) send_vaddress_for_cache_index;
+       method Action translation_protection_frm_csr(bit tlb_disable, Chmod per_bits, Bit#(TAdd#(4,`ASID)) asid);
+       interface Get#(Request_PPN_PTW#(`VADDR,`OFFSET)) to_PTW; 
+       interface Put#(Tuple2#(Bool, To_TLB#(`PADDR,`OFFSET,`ASID))) refill_TLB;
+       method Action flush(Bool _flush);
+       method Action fence_TLB(Fence_VMA_type#(`VADDR) rsdata);
+       //method ActionValue#(Bool) page_fault;
+       //method Action page_fault_frm_PTW;
+endinterface
+
+(*mutually_exclusive="refill_TLB_put, send_ppn"*)
+(*synthesize*)
+module mkdTLB(Ifc_dTLB);
+
+Ifc_TLB#(`ADDR,`VADDR,`PADDR,`OFFSET,`ASID) dtlb <- mkTLB();
+
+       method Action get_vaddr(DTLB_access#(`ADDR) addr `ifdef atomic , Bit#(5) atomic `endif );
+               dtlb.get_vaddr(addr `ifdef atomic ,atomic `endif );
+       endmethod
+       method ActionValue#(From_TLB#(`ADDR)) send_ppn = dtlb.send_ppn;
+       method ActionValue#(Bit#(`VADDR)) send_vaddress_for_cache_index = dtlb.send_vaddress_for_cache_index;
+       method Action translation_protection_frm_csr(bit tlb_disable, Chmod per_bits, Bit#(TAdd#(4,`ASID)) asid);
+               dtlb.translation_protection_frm_csr(tlb_disable,per_bits,asid);
+       endmethod
+       interface  to_PTW = dtlb.to_PTW; 
+       interface  refill_TLB = dtlb.refill_TLB;
+       method Action flush(Bool _flush);
+               dtlb.flush(_flush);
+       endmethod
+       method Action fence_TLB(Fence_VMA_type#(`VADDR) rsdata);
+               dtlb.fence_TLB(rsdata);
+       endmethod
+       
+       //method ActionValue#(Bool) page_fault = dtlb.page_fault;
+       //method Action page_fault_frm_PTW = dtlb.page_fault_frm_PTW;
+endmodule
+
+endpackage
diff --git a/src/core/dcache_asic.bsv b/src/core/dcache_asic.bsv
new file mode 100644 (file)
index 0000000..4a139f5
--- /dev/null
@@ -0,0 +1,745 @@
+/*
+Copyright (c) 2013, IIT Madras
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+*  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+*  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+*  Neither the name of IIT Madras  nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+*/
+package dcache_asic;
+       /*===== Pacakge imports ===== */
+       import BRAMCore::*;
+       import FIFO::*;
+       import FIFOF::*;
+       import SpecialFIFOs::*;
+       import LFSR::*;
+       import ConfigReg::*;
+       import DReg::*;
+       import BUtils::*;
+       import MemoryMap::*;
+       import mem_config1::*;
+       import Vector::*;
+       /*===== project imports==== */
+       import defined_types::*;
+       `include "defined_parameters.bsv"
+       import QuadMem::*;
+       import Assert::*;
+       /*========================= */
+       interface Ifc_dcache;
+               method Action virtual_address(Bit#(`VADDR) vaddress, Access_type load_store, Bit#(TMul#(`DCACHE_WORD_SIZE,8)) writedata, Bit#(3) transfer_size, `ifdef atomic Bit#(5) atomic_op, `endif Bool signextend, Bit#(1) insnepoch);
+               method Maybe#(Tuple4#(Bit#(`Reg_width), Trap_type,Bit#(`PERFMONITORS),Bit#(1))) response_to_core;
+               method ActionValue#(To_Memory#(`PADDR)) read_request_to_memory;
+               method ActionValue#(To_Memory_Write) write_request_to_memory;
+               method Action read_response_from_memory(From_Memory#(`DCACHE_WORD_SIZE) resp);
+               method Action write_response_from_memory(From_Memory#(`DCACHE_WORD_SIZE) resp);
+               method Bool init_complete;
+               method Action flush_from_wb;
+               `ifdef MMU
+                       method Action physical_address(Bit#(`PADDR) paddr, Trap_type exception);
+               `endif
+       endinterface
+
+       typedef enum {Idle,Dummy,KeepPolling,Stall1,ReadingCache,Initialize,Fence,FenceStart,IOReadResp,IOWriteResp} DcacheState deriving (Bits,Eq,FShow);
+
+       (*synthesize*)
+       (*conflict_free="virtual_address,pre_fence_updating"*)
+       (*conflict_free="virtual_address,handle_fence"*)
+       (*conflict_free="keep_polling_on_stall,handle_fence"*)
+       (*conflict_free="keep_polling_on_stall,pre_fence_updating"*)
+       (*conflict_free="keep_polling_on_stall,wait_for_ioread_response"*)
+       (*conflict_free="keep_polling_on_stall,wait_for_iowrite_response"*)
+       (*conflict_free="dummy_cycle,read_from_lbdata_into_hold_reg"*)
+       (*preempts="virtual_address,read_from_lbdata_into_hold_reg"*)
+//     (*preempts="keep_polling_on_stall,read_from_lbdata_into_hold_reg"*)
+       (*preempts="stall_the_next_request_by_one_cycle,read_from_lbdata_into_hold_reg"*)
+       (*preempts="read_from_lbdata_into_hold_reg,keep_polling_on_stall"*)
+       module mkdcache(Ifc_dcache);
+               /* VAddr = [tag_bits|set_bits|word_bits|byte_bits] */
+               let byte_bits=valueOf(TLog#(`DCACHE_WORD_SIZE));        // number of bits to select a byte within a word. = 2
+               let word_bits=valueOf(TLog#(`DCACHE_BLOCK_SIZE));       // number of bits to select a word within a block. = 4
+               let set_bits=valueOf(TLog#(`DCACHE_SETS));                      // number of bits to select a set from the cache. = 
+               Reg#(Maybe#(Tuple2#(Bit#(1),Bit#(`PADDR)))) rg_lr_paddress<-mkReg(tagged Invalid);
+               `ifdef atomic
+               function ActionValue#(Tuple3#(Maybe#(Bit#(1)),Bool, Bit#(TMul#(`DCACHE_WORD_SIZE,8)))) atomic_operation(Bit#(TMul#(`DCACHE_WORD_SIZE,8)) loaded_value, Bit#(TMul#(`DCACHE_WORD_SIZE,8)) rs2, Bit#(5) atomic_op, Bit#(`PADDR) addr);
+               return (
+               actionvalue 
+                       Bit#(TMul#(`DCACHE_WORD_SIZE,8)) atomic_result=rs2;
+                       Bit#(TMul#(`DCACHE_WORD_SIZE,8)) op1;
+                       Maybe#(Bit#(1)) sc_done=tagged Invalid;
+                       if(atomic_op[4]==1)
+                               op1=signExtend(loaded_value[31:0]);
+                       else
+                               op1=loaded_value;
+                       Bit#(TMul#(`DCACHE_WORD_SIZE,8)) op2=(atomic_op[4]==1)?signExtend(rs2[31:0]):rs2;
+                       Int#(TMul#(`DCACHE_WORD_SIZE,8)) s_op1=unpack(op1);
+                       Int#(TMul#(`DCACHE_WORD_SIZE,8)) s_op2 = unpack(op2);
+                       Bool store_result = True;
+                       `ifdef verbose $display($time,"\tDCACHE: atomic instruction atomic op %b op1: %h op2: %h", atomic_op,op1,op2); `endif
+                       case (atomic_op[3:0])
+                               'b0011:atomic_result=op2;
+                               'b0000:atomic_result= (op1+op2);
+                               'b0010:atomic_result= (op1^op2);
+                               'b0110:atomic_result= (op1&op2);
+                               'b0100:atomic_result= (op1|op2);
+                               'b1100:atomic_result= min(op1,op2);
+                               'b1110:atomic_result= max(op1,op2);
+                               'b1000:atomic_result= pack(min(s_op1,s_op2));
+                               'b1010:atomic_result= pack(max(s_op1,s_op2));
+                               default:        begin atomic_result= op1; end
+                       endcase 
+                       case (atomic_op[3:0])
+                               'b0101: begin 
+                                                               rg_lr_paddress <= tagged Valid tuple2(atomic_op[4],addr);
+                                                               atomic_result=loaded_value; // LR
+                                                               store_result = False;
+                                                       end
+                               'b0111: begin
+                                                               rg_lr_paddress <= tagged Invalid;
+                                                               atomic_result=rs2;                        // SC
+                                                               sc_done = tagged Valid 1;
+                                                               store_result = False;
+                                                               `ifdef verbose $display($time,"\tDCACHE: store condition instruction"); `endif
+                                                               if(rg_lr_paddress matches tagged Valid .lr) begin
+                                                                       let {x,y} = lr;
+                                                                       if(x==atomic_op[4] && addr== y) begin
+                                                                               `ifdef verbose $display($time,"\tDCACHE: store condition satisfied"); `endif
+                                                                               sc_done = tagged Valid 0;
+                                                                               store_result = True;
+                                                                 end
+                                                               end
+                                                       end
+                               default:        begin rg_lr_paddress<=tagged Invalid ;end
+                       endcase 
+                       if(atomic_op[4]==1)
+                                       atomic_result=duplicate(atomic_result[31:0]);
+
+                       return tuple3(sc_done,store_result,atomic_result);
+                       endactionvalue );
+               endfunction
+               `endif
+               function Bit#(TMul#(TMul#(8,`DCACHE_WORD_SIZE),`DCACHE_BLOCK_SIZE)) update_line (Bit#(TMul#(`DCACHE_BLOCK_SIZE,`DCACHE_WORD_SIZE)) we, Bit#(TMul#(TMul#(8,`DCACHE_WORD_SIZE),`DCACHE_BLOCK_SIZE)) data, Bit#(TMul#(TMul#(8,`DCACHE_WORD_SIZE),`DCACHE_BLOCK_SIZE)) data_reg);
+         Bit#(TMul#(TMul#(8,`DCACHE_WORD_SIZE),`DCACHE_BLOCK_SIZE)) mask=0;
+         for(Integer i=0;i<32;i=i+1)begin
+            Bit#(8) ex_we=duplicate(we[i]);
+            mask[(i*8)+7:i*8]=ex_we;
+         end
+         Bit#(TMul#(TMul#(8,`DCACHE_WORD_SIZE),`DCACHE_BLOCK_SIZE)) x = mask& data;
+         Bit#(TMul#(TMul#(8,`DCACHE_WORD_SIZE),`DCACHE_BLOCK_SIZE)) y = ~mask& data_reg;
+         data_reg=x|y;
+                       return data_reg;
+      endfunction
+               
+               Ifc_dcache_data data [`DCACHE_WAYS];
+               Ifc_dcache_tag   tag  [`DCACHE_WAYS];
+               for(Integer i=0;i<`DCACHE_WAYS;i=i+1)begin
+                       tag[i] <- mkdcache_tag;         
+                       data[i] <-mkdcache_data;
+               end
+
+               /*====== Hit buffer data structur======*/
+               Reg#(Bool) hb_valid <-mkReg(False);
+               Reg#(Bit#(`DCACHE_WAYS)) hb_way <-mkReg(0);
+               Reg#(Bit#(`DCACHE_TAG_BITS)) hb_tag <-mkReg(0);
+               Reg#(Bit#(TLog#(`DCACHE_SETS))) hb_setindex <- mkReg(0);
+               Ifc_QuadMem hb_data <-mkQuadMem;
+               /*=====================================*/
+
+               /*-====== Line buffer data structure ====*/
+               Ifc_QuadMem lb_data <-mkQuadMem;
+               FIFOF#(Tuple4#(Bit#(20),Bit#(TLog#(`DCACHE_SETS)),Bit#(`DCACHE_WAYS),Bit#(TMul#(`DCACHE_WORD_SIZE,`DCACHE_BLOCK_SIZE)))) memoperation <-mkUGSizedFIFOF(2);
+               Reg#(Bit#(1)) lb_dirty <-mkReg(0);
+               Reg#(Bit#(TMul#(`DCACHE_WORD_SIZE,`DCACHE_BLOCK_SIZE))) line_bytes_written<-mkReg(0);
+               /*=====================================*/
+
+               /*======= Request Capture =========*/
+               Reg#(Bit#(`VADDR)) rg_vaddress <-mkReg(0);
+               Reg#(Bit#(`PADDR)) rg_paddress <-mkReg(0);
+               Reg#(Bit#(`PADDR)) rg_poll_address <-mkReg(0);
+               Reg#(Bit#(3))           rg_transfer_size <-mkReg(0);
+               `ifdef atomic Reg#(Bit#(5))             rg_atomic_op <-mkReg(0); `endif
+               Reg#(Access_type) rg_access_type <-mkReg(Load);
+               Reg#(Bit#(TMul#(`DCACHE_WORD_SIZE,`DCACHE_BLOCK_SIZE))) rg_writeenable<-mkReg(0);
+               Reg#(Bool) rg_signextend<-mkReg(False);
+               Reg#(Bool)              misaligned_addr <-mkReg(False);
+               Reg#(Bit#(1))           rg_insn_epoch <-mkReg(0);
+               Reg#(Bit#(TMul#(`DCACHE_WORD_SIZE,8))) rg_writedata<-mkReg(0);
+               /*=================================*/
+               /* storage for physical translation */
+               Reg#(Bool)      rg_trnslte_done[2] <- mkCReg(2,`ifdef MMU False `else True `endif );
+               Reg#(Trap_type) rg_tlb_exception[2]<-mkCReg(2,tagged None);
+               /*==================================== */
+
+               /*===== registers for fencing/initializing ====*/
+               Reg#(Bit#(TLog#(`DCACHE_SETS))) fence_set <-mkReg(0);
+               Reg#(Bit#(TLog#(`DCACHE_WAYS))) fence_way <-mkReg(0);
+               /*==============================================*/
+               
+               /*========= FIFO for interfaces ================*/
+               FIFOF#(To_Memory#(`PADDR)) ff_read_request_to_memory <-mkLFIFOF();
+               FIFOF#(To_Memory_Write) ff_write_request_to_memory <-mkLFIFOF();
+               FIFOF#(From_Memory#(`DCACHE_WORD_SIZE)) ff_read_response_from_memory <-mkSizedBypassFIFOF(1);
+               FIFOF#(From_Memory#(`DCACHE_WORD_SIZE)) ff_write_response_from_memory <-mkSizedBypassFIFOF(1);
+               /*===============================================*/
+
+               /*===== State Registers========*/
+               Reg#(Bit#(1)) wbEpoch [3]  <-mkCReg(3,0);
+               Reg#(DcacheState)         rg_state[3]   <-mkCReg(3,Initialize);
+               /*============================*/
+
+               /*============ globals =========*/
+               Reg#(Bool) rg_global_dirty <-mkReg(False);
+               Wire#(Maybe#(Tuple2#(Bit#(20),Bit#(TLog#(`DCACHE_SETS))))) wr_write_info<-mkDWire(tagged Invalid);      
+               Wire#(Maybe#(Tuple4#(Bit#(`Reg_width), Trap_type, Bit#(`PERFMONITORS),Bit#(1)))) wr_response_to_cpu<-mkDWire(tagged Invalid);
+               Reg#(Bit#(`PERFMONITORS)) rg_perf_monitor<-mkReg(0);
+               LFSR#(Bit#(2)) random_line<-mkRCounter(3);                                                              // for random line replacement
+               Reg#(Bool) pending_write_response[3]<-mkCReg(3,False);
+               Reg#(Bool) capture_counters <-mkDReg(False);
+               Reg#(Bool) rg_initialize <-mkReg(True);
+               Reg#(Bit#(TMul#(`DCACHE_WORD_SIZE,`DCACHE_BLOCK_SIZE))) rg_we<-mkReg(0);
+               Reg#(Bool) rg_bus_error<-mkReg(False);
+               /*==============================*/
+               rule display_state;
+                       `ifdef verbose $display($time,"\tDCACHE: state ",fshow(rg_state[0])," wbEpoch: %b",wbEpoch[0]); `endif
+               endrule
+
+               rule dummy_cycle(rg_state[1]==Dummy);
+                       rg_state[1]<=Idle;
+               endrule
+
+               rule deq_write_response_during_fence(pending_write_response[2]);
+                       ff_write_response_from_memory.deq;
+                       pending_write_response[2]<=False;
+               endrule
+               rule pre_fence_updating(rg_state[0]==FenceStart && !memoperation.notEmpty && !pending_write_response[2]);
+                       if(wbEpoch[0]==rg_insn_epoch)begin
+                               if(hb_valid)begin
+                                       for(Integer i=0;i<`DCACHE_WAYS;i=i+1)begin      
+                                               tag[i].write_request(unpack(hb_way[i]),hb_setindex,{2'b11,hb_tag});
+                                               data[i].write_request(duplicate(hb_way[i]),hb_setindex,hb_data.response_portA);
+                                       end
+                                       hb_valid<=False;
+                               end
+                               else begin
+                                       rg_state[0]<=Fence;
+                                       tag[0].read_request(0);
+                                       data[0].read_request(0);
+                                       fence_set<=0;
+                                       fence_way<=0;
+                               end
+                       end
+                       else begin
+                               wr_response_to_cpu<=tagged Valid (tuple4(0,tagged None, 0, rg_insn_epoch));
+                       end
+               endrule
+               /*====== Invalidate all the entries in the cache on startup or during Fence ==== */
+               rule fencing_the_cache(rg_state[0]==Initialize && !memoperation.notEmpty && !pending_write_response[2]);
+                       `ifdef verbose $display($time,"\tDCACHE: Initializing index: %d",fence_set," ",fshow(rg_access_type)); `endif
+                       for(Integer i=0;i<`DCACHE_WAYS;i=i+1)begin
+                               tag[i].write_request(True,truncate(fence_set),0);
+                       end
+                       if(fence_set==fromInteger(`DCACHE_SETS-1)) begin
+                               rg_state[0]<=Dummy;
+                               fence_set<=0;
+                               fence_way<=0;
+                               random_line.seed('d3);
+                               rg_global_dirty<=False;
+                               rg_trnslte_done[0]<=False;
+                               if(rg_access_type==Fence)
+                                       wr_response_to_cpu<= tagged Valid (tuple4(0,tagged None,0,rg_insn_epoch));
+                       end
+                       else
+                               fence_set<=fence_set+1;
+               endrule
+               /*=============================================================================== */
+               rule handle_fence(rg_state[0]==Fence &&!memoperation.notEmpty);
+                       Bit#(20) tag_values=tag[fence_way].read_response[20-1:0];       // hold the tag values
+                       Bit#(1) dirty_value=tag[fence_way].read_response[20+1];         // holds the dirty bits
+                       Bit#(1) valid_value=tag[fence_way].read_response[20];           // holds the dirty bits
+                       Bit#(TMul#(8,TMul#(`DCACHE_WORD_SIZE,`DCACHE_BLOCK_SIZE))) data_values; // holds the cache lines.
+                       Bit#(TAdd#(TLog#(`DCACHE_WORD_SIZE),TLog#(`DCACHE_BLOCK_SIZE))) p_offset =0;
+                       data_values=data[fence_way].read_response;
+
+                       Bit#(`PADDR) write_addr={tag_values,truncate(fence_set),p_offset};
+                       `ifdef verbose $display($time,"\tDCACHE: Handling Fence.tag %h setindex: %d fence_way: %d Dirty: %b Valid: %b",tag_values,fence_set,fence_way,dirty_value,valid_value); `endif
+                       `ifdef verbose $display($time,"\tDCACHE: Fence addr: %h line: %h ",write_addr,data_values); `endif 
+                       Bit#(TLog#(`DCACHE_SETS)) new_set=fence_set;
+                       Bit#(TLog#(`DCACHE_SETS)) old_set=fence_set;
+                       Bit#(TLog#(`DCACHE_WAYS)) next_way=fence_way;
+                       if(!pending_write_response[1])begin
+                               if(dirty_value==1 && valid_value==1)begin // valid and dirty
+                                       ff_write_request_to_memory.enq(To_Memory_Write { // send the request to memory to 
+                        address:write_addr,  data_line:data_values,
+                                                       burst_length:`DCACHE_BLOCK_SIZE,  transfer_size:3, ld_st:Store});
+                                       pending_write_response[1]<=True;
+                               end
+                               if(fence_way==fromInteger(`DCACHE_WAYS-1))begin
+                                       new_set=fence_set+1;
+                                       if(fence_set==fromInteger(`DCACHE_SETS-1))begin
+                                               rg_state[0]<=Dummy;
+                                               rg_global_dirty<=False;
+                                               wr_response_to_cpu<= tagged Valid (tuple4(0,tagged None,0,rg_insn_epoch));
+                                               rg_trnslte_done[0]<=False;
+                                               fence_set<=0;
+                                       end
+                                       else
+                                               fence_set<=new_set;
+                               end
+                               next_way=fence_way+1;
+                               tag[fence_way].write_request(True,old_set,0);
+                       end
+                       `ifdef verbose $display($time,"\tDCACHE: FENCE: sending request to setindex: %d way: %d",new_set,next_way); `endif
+                       tag[next_way].read_request(new_set);
+                       data[next_way].read_request(new_set);
+                       fence_way<=next_way;
+               endrule
+
+               rule read_from_lbdata_into_hold_reg(line_bytes_written=='1 && memoperation.notEmpty);
+                       let lb_hold_reg=lb_data.response_portB;
+                       let {cputag,setindex,replaceblock,writeenable}=memoperation.first;
+                       for(Integer i=0;i<`DCACHE_WAYS;i=i+1)begin      
+                               tag[i].write_request((unpack(replaceblock[i])&&True),setindex,{lb_dirty,1'b1,cputag});
+                               data[i].write_request(duplicate(replaceblock[i]),setindex,lb_hold_reg);
+                       end
+                       line_bytes_written<=0;
+                       lb_dirty<=0;
+                       memoperation.deq;
+                       rg_bus_error<=False;
+                       `ifdef verbose $display($time,"\tDCACHE: capturing lbdata cpu_tag: %h setindex: %d addr: %h linenum: %b data: %h",cputag, setindex,{cputag,setindex,6'd0}, replaceblock,lb_hold_reg); `endif
+                       if(rg_state[1]==KeepPolling)
+                               rg_state[1]<=Stall1;
+               endrule
+               
+               rule fillcache(memoperation.notEmpty && line_bytes_written!='1); // need to check line_bytes_written to ensure the same response is being served.
+                       let memresp=ff_read_response_from_memory.first;
+                       ff_read_response_from_memory.deq;
+                       rg_bus_error<=unpack(memresp.bus_error)||rg_bus_error;
+                       let {cpu_tag,setindex,replaceblock,writeenable}=memoperation.first;
+                       `ifdef verbose $display($time,"\tDCACHE: Response from Memory: %h setindex: %d cpu_tag: %h replaceblock: %b",memresp.data_line,setindex,cpu_tag,replaceblock); `endif 
+                       let we=writeenable;
+                       if(|line_bytes_written!=0)begin
+                               we=rg_we;
+                       end
+                       Bit#(TMul#(2,TMul#(`DCACHE_WORD_SIZE,`DCACHE_BLOCK_SIZE))) extended_mask=zeroExtend(we)<<8;
+                       lb_data.write_portB(we,duplicate(memresp.data_line));
+                       `ifdef verbose $display($time,"\tDCACHE: linebytes: %h currently writing into: %h",line_bytes_written,we); `endif
+                       if(memresp.last_word)begin // if all the data words have been fetched exit      
+                               `ifdef verbose $display($time,"\tDCACHE: Received Last response from Memory set: %d ",setindex); `endif
+                       end
+                       line_bytes_written<=line_bytes_written|we;
+                       rg_we<=extended_mask[2*`DCACHE_BLOCK_SIZE*`DCACHE_WORD_SIZE-1:`DCACHE_BLOCK_SIZE*`DCACHE_WORD_SIZE]|extended_mask[`DCACHE_BLOCK_SIZE*`DCACHE_WORD_SIZE-1:0];
+               endrule
+
+               rule drop_incoming_request(rg_state[0]==ReadingCache && memoperation.notFull && wbEpoch[0]!=rg_insn_epoch);
+                       if(rg_trnslte_done[0])
+                               wr_response_to_cpu<=tagged Valid (tuple4(0,tagged None, 0, rg_insn_epoch));
+                       `ifdef verbose $display($time,"\tDCACHE: Dropping incoming request wbEpoch: %b rg_insn_epoch: %b",wbEpoch[0],rg_insn_epoch); `endif
+                       rg_trnslte_done[0]<=False;
+                       rg_state[0]<=Idle;
+               endrule
+               /*============== One cycle delay to ensure the write is reflected in the BRAM ========= */
+               rule stall_the_next_request_by_one_cycle(rg_state[1]==Stall1);
+                       Bit#(TLog#(`DCACHE_SETS)) setindex=rg_vaddress[set_bits+word_bits+byte_bits-1:word_bits+byte_bits];
+                       for(Integer i=0;i<`DCACHE_WAYS;i=i+1)begin // send address to the Block_rams
+                               tag[i].read_request(setindex);
+                               data[i].read_request(setindex);
+                       end
+                       rg_state[1]<=ReadingCache;
+               endrule
+               /*===================================================================================== */
+               
+               rule keep_polling_on_stall(rg_state[1]==KeepPolling);
+                       Bit#(`PERFMONITORS) perf_monitor=rg_perf_monitor;
+                       if(capture_counters)begin
+                               `ifdef verbose $display($time,"\tDCACHE: Miss during polling for ",fshow(rg_access_type)); `endif
+                               if(rg_access_type==Load)begin
+                                       perf_monitor[`DCACHE_LOAD_MISS]=1;
+                                       perf_monitor[`DCACHE_CACHEABLE_LOAD]=1;
+                               end
+                               else if(rg_access_type==Store)begin
+                                       perf_monitor[`DCACHE_STORE_MISS]=1;
+                                       perf_monitor[`DCACHE_CACHEABLE_STORE]=1;
+                               end
+                               else if(rg_access_type==Atomic) begin
+                                       perf_monitor[`DCACHE_ATOMIC_MISS]=1;
+                                       perf_monitor[`DCACHE_CACHEABLE_ATOMIC]=1;
+                               end
+                               rg_perf_monitor<=perf_monitor;
+                       end
+                       Bit#(TLog#(`DCACHE_SETS)) setindex=rg_vaddress[set_bits+word_bits+byte_bits-1:word_bits+byte_bits];
+                       Bit#(20) cpu_tag=rg_poll_address[`PADDR-1:`PADDR-20];
+                       let {lbtag,lbset,lbreplaceblock,lbwriteenable}=memoperation.first;
+                       if((line_bytes_written & rg_writeenable) == rg_writeenable && (lbset==setindex && lbtag==cpu_tag))begin
+                               `ifdef verbose $display($time,"\tDCACHE: Accessing LB"); `endif
+                               rg_state[1]<=ReadingCache; 
+                               for(Integer i=0;i<`DCACHE_WAYS;i=i+1)begin // send address to the Block_rams
+                                       tag[i].read_request(setindex);
+                                       data[i].read_request(setindex);
+                               end
+                       end
+                       `ifdef verbose $display($time,"\tDCACHE: Polling on LB. cpu_tag: %h lbtag: %h required: %h bytes in Buffer: %h",cpu_tag,lbtag,rg_writeenable,line_bytes_written); `endif
+               endrule
+
+
+               rule read_from_memory_structures(rg_state[0]==ReadingCache && memoperation.notFull && wbEpoch[0]==rg_insn_epoch);
+                       Bool cache_enabled = !is_IO_Addr(rg_paddress);
+                       Trap_type exception = misaligned_addr?((rg_access_type==Load)?
+                                       tagged Exception Load_addr_misaligned:tagged Exception Store_addr_misaligned): rg_bus_error?
+                                               (rg_access_type==Load?tagged Exception Load_access_fault:tagged Exception Store_access_fault):rg_tlb_exception[0];
+                       /*====== Get the states of the request ======*/
+                       Bit#(20) cpu_tag=rg_paddress[`PADDR-1:`PADDR-20];
+                       Bit#(TLog#(`DCACHE_BLOCK_SIZE)) word_offset=rg_vaddress[word_bits+byte_bits-1:byte_bits];
+                       Bit#(TLog#(`DCACHE_WORD_SIZE))  byte_offset=rg_vaddress[byte_bits-1:0];
+                       Bit#(TLog#(`DCACHE_SETS))                       setindex=rg_vaddress[set_bits+word_bits+byte_bits-1:word_bits+byte_bits];
+
+                       Bit#(TMul#(TMul#(`DCACHE_BLOCK_SIZE,`DCACHE_WORD_SIZE),8)) hbdataline=0;
+                       Bit#(TMul#(TMul#(`DCACHE_BLOCK_SIZE,`DCACHE_WORD_SIZE),8)) lbdataline=0;
+                                               
+                       /*========== Check hit on Hit buffer =======*/
+                       Bool hb_hit = False;
+                       if(hb_valid && (hb_setindex==setindex) && (hb_tag==cpu_tag) && !misaligned_addr)begin
+                               hb_hit=True;
+                               hbdataline=hb_data.response_portA;
+                       end
+                       /*==========================================*/
+
+                       /*========= Check Line buffer ==============*/
+                       Bool stall_on_lb=((line_bytes_written & rg_writeenable) != rg_writeenable) && memoperation.notEmpty;
+                       Bool lb_valid=memoperation.notEmpty;
+                       let {lb_tag,lb_setindex,lb_way,lb_we}=memoperation.first;
+                       Bool lb_hit = False;
+                       if(lb_valid && (lb_setindex==setindex) && (lb_tag==cpu_tag) && !misaligned_addr)begin
+                               lb_hit=True;
+                               lbdataline=lb_data.response_portA;
+                       end
+                       /*===========================================*/
+
+                       /*======= Check SRAMS ==============*/
+                       Bit#(`DCACHE_WAYS) tag_hit=0;
+
+                       Bit#(TMul#(TMul#(`DCACHE_BLOCK_SIZE,`DCACHE_WORD_SIZE),8)) dataline0=data[0].read_response;
+                       Bit#(TMul#(TMul#(`DCACHE_BLOCK_SIZE,`DCACHE_WORD_SIZE),8)) dataline1=data[1].read_response;
+                       Bit#(TMul#(TMul#(`DCACHE_BLOCK_SIZE,`DCACHE_WORD_SIZE),8)) dataline2=data[2].read_response;
+                       Bit#(TMul#(TMul#(`DCACHE_BLOCK_SIZE,`DCACHE_WORD_SIZE),8)) dataline3=data[3].read_response;
+
+                       Bit#(`DCACHE_WAYS) valid_values={tag[3].read_response[20],tag[2].read_response[20],tag[1].read_response[20],tag[0].read_response[20]};
+                       Bit#(`DCACHE_WAYS) dirty_values={tag[3].read_response[21],tag[2].read_response[21],tag[1].read_response[21],tag[0].read_response[21]};
+                                               
+                       if(cpu_tag==tag[0].read_response[19:0] && valid_values[0]==1) tag_hit[0]=1; 
+                       if(cpu_tag==tag[1].read_response[19:0] && valid_values[1]==1) tag_hit[1]=1; 
+                       if(cpu_tag==tag[2].read_response[19:0] && valid_values[2]==1) tag_hit[2]=1; 
+                       if(cpu_tag==tag[3].read_response[19:0] && valid_values[3]==1) tag_hit[3]=1; 
+                       
+                       Bool hit=False;
+                       hit=unpack(|(tag_hit)) && (!hb_hit) && (!lb_hit) && !misaligned_addr;
+                       // We are not invalidating a replaced line when enquing into the linebuffer.
+                       // So it is possible that the next request finds this to be a hit and proceeds to change the SRAM.
+                       // While the linebuffer, having received all the bytes from the memory will simply
+                       // go ahead and replace the dirty line without eviction. The following condition ensures
+                       // that for the same index if the SRAM hit is to the same line as the LB treat is as a miss.
+                       if(hit && tag_hit==lb_way && lb_valid && lb_setindex==setindex)
+                               hit=False;
+                       dynamicAssert(!(lb_hit&&hb_hit),"ASSERT: lb_hit and hb_hit are both 1");
+                       
+                       Bit#(TMul#(TMul#(`DCACHE_BLOCK_SIZE,`DCACHE_WORD_SIZE),8)) temp0=duplicate(tag_hit[0]&pack(hit));
+                       Bit#(TMul#(TMul#(`DCACHE_BLOCK_SIZE,`DCACHE_WORD_SIZE),8)) temp1=duplicate(tag_hit[1]&pack(hit));
+                       Bit#(TMul#(TMul#(`DCACHE_BLOCK_SIZE,`DCACHE_WORD_SIZE),8)) temp2=duplicate(tag_hit[2]&pack(hit));
+                       Bit#(TMul#(TMul#(`DCACHE_BLOCK_SIZE,`DCACHE_WORD_SIZE),8)) temp3=duplicate(tag_hit[3]&pack(hit));
+                       Bit#(TMul#(TMul#(`DCACHE_BLOCK_SIZE,`DCACHE_WORD_SIZE),8)) hitline0=temp0&dataline0;
+                       Bit#(TMul#(TMul#(`DCACHE_BLOCK_SIZE,`DCACHE_WORD_SIZE),8)) hitline1=temp1&dataline1;
+                       Bit#(TMul#(TMul#(`DCACHE_BLOCK_SIZE,`DCACHE_WORD_SIZE),8)) hitline2=temp2&dataline2;
+                       Bit#(TMul#(TMul#(`DCACHE_BLOCK_SIZE,`DCACHE_WORD_SIZE),8)) hitline3=temp3&dataline3;
+                       Bit#(TMul#(TMul#(`DCACHE_BLOCK_SIZE,`DCACHE_WORD_SIZE),8)) sram_dataline=hitline0|hitline1|hitline2|hitline3;
+                       `ifdef verbose $display($time,"\tDCACHE: valid_values: %b dirty_values: %b stall_on_lb: %b we: %h Access_type: ",valid_values,dirty_values,stall_on_lb,rg_writeenable,fshow(rg_access_type)); `endif
+                       /*================================================*/
+                       /*===== replacement line selection ==============*/
+                       Bit#(`DCACHE_WAYS) replace_vec=valid_values;
+                       if(&(valid_values)==1)
+                               replace_vec=dirty_values;
+                       case (replace_vec) matches
+                               'b???0:replace_vec='b0001;
+                               'b??01:replace_vec='b0010;
+                               'b?011:replace_vec='b0100;
+                               'b0111:replace_vec='b1000;
+                               default:begin 
+                                       replace_vec=0;
+                                       replace_vec[random_line.value]=1;
+                                       random_line.next;
+                               end
+                       endcase
+                       if(replace_vec==lb_way && lb_setindex==setindex && lb_valid)
+                               replace_vec=rotateBitsBy(lb_way,1);
+                       if(replace_vec==hb_way && hb_valid && hb_setindex==setindex)
+                               replace_vec=rotateBitsBy(replace_vec,1);
+                       `ifdef verbose $display($time,"\tDCACHE: replacevec: %b hb_way: %b lb_way: %b",replace_vec,hb_way,lb_way);      `endif
+                       `ifdef verbose $display($time,"\tDCACHE: CPUTAG: %h lb_tag: %h hb_tag :%h",cpu_tag,lb_tag,hb_tag); `endif
+                       `ifdef verbose $display($time,"\tDCACHE: CPUIndex: %d lb_index: %d hb_inex :%d",setindex,lb_setindex,hb_setindex); `endif
+                       
+                       Bit#(TAdd#(TLog#(`DCACHE_WORD_SIZE),TLog#(`DCACHE_BLOCK_SIZE))) offset_zeros='d0;
+                       Bit#(`PADDR) r0=duplicate(replace_vec[0]);
+                       Bit#(`PADDR) r1=duplicate(replace_vec[1]);
+                       Bit#(`PADDR) r2=duplicate(replace_vec[2]);
+                       Bit#(`PADDR) r3=duplicate(replace_vec[3]);
+                       Bit#(`PADDR) write_address0=r0&{tag[0].read_response[20-1:0],setindex[6:0],offset_zeros};
+                       Bit#(`PADDR) write_address1=r1&{tag[1].read_response[20-1:0],setindex[6:0],offset_zeros};
+                       Bit#(`PADDR) write_address2=r2&{tag[2].read_response[20-1:0],setindex[6:0],offset_zeros};
+                       Bit#(`PADDR) write_address3=r3&{tag[3].read_response[20-1:0],setindex[6:0],offset_zeros};
+                       Bit#(`PADDR) write_address = write_address0 | write_address1 | write_address2 | write_address3;
+                       Bit#(TMul#(TMul#(`DCACHE_BLOCK_SIZE,`DCACHE_WORD_SIZE),8)) replace_dataline =
+                               case(replace_vec)
+                                       'b0001:dataline0; 
+                                       'b0010:dataline1; 
+                                       'b0100:dataline2;
+                                       'b1000:dataline3;
+                                       default:0;
+                               endcase;
+                       `ifdef verbose $display($time,"\tDCACHE: Replace vec: %h line: %h address :%h",replace_vec,replace_dataline, write_address); `endif
+                       /*==============================================*/
+
+                       /*==== capture the word to be operated on and perform the atomic operation as well on it=======*/
+                       Bit#(TMul#(TMul#(`DCACHE_BLOCK_SIZE,`DCACHE_WORD_SIZE),8)) dataline=hbdataline|lbdataline|sram_dataline;
+                       Bit#(`Reg_width) data_word=(dataline>>{6'd0,word_offset}*64)[`Reg_width-1:0];
+                       data_word=data_word>>({4'b0,byte_offset}*8);
+
+                       if(!rg_signextend)
+                               data_word=rg_transfer_size==0?zeroExtend(data_word[7:0]):rg_transfer_size==1?zeroExtend(data_word[15:0]):rg_transfer_size==2?zeroExtend(data_word[31:0]):data_word;
+                       else
+                               data_word=rg_transfer_size==0?signExtend(data_word[7:0]):rg_transfer_size==1?signExtend(data_word[15:0]):rg_transfer_size==2?signExtend(data_word[31:0]):data_word;
+                       `ifdef atomic 
+                               let {success,storeResult,atomicdata} <- atomic_operation(data_word,rg_writedata,rg_atomic_op,rg_paddress); 
+                               if(rg_access_type==Load)
+                                       storeResult=False;
+                               if(success matches tagged Valid .sc)
+                                       data_word = zeroExtend(sc);
+                       `endif
+                       Bit#(`Reg_width) final_word = `ifdef atomic (rg_access_type==Atomic)?atomicdata: `endif (rg_access_type==Store)?rg_writedata:data_word;
+                       `ifdef verbose $display($time,"\tDCACHE: hbhit: %b hbdataline: %h",hb_hit,hbdataline); `endif
+                       `ifdef verbose $display($time,"\tDCACHE: lb_hit: %b lbdataline: %h",lb_hit,lbdataline); `endif
+                       `ifdef verbose $display($time,"\tDCACHE: tag_hit: %b hit  : %b srdataline: %h",tag_hit,hit , sram_dataline); `endif
+                       `ifdef verbose $display($time,"\tDCACHE: Sending to Core: %h Final line: %h",data_word,dataline); `endif
+                       `ifdef verbose $display($time,"\tDCACHE: translation done: %b tlb_exception: ",rg_trnslte_done[0],fshow(rg_tlb_exception[0])); `endif
+                       /*=============================================================================================*/
+                       /*============ perform Store/Atomic operations =============*/
+                       if(rg_trnslte_done[0] &&& rg_tlb_exception[0] matches tagged None)begin
+                       if(cache_enabled)begin
+                               /*======= Calculate the next state ===*/
+                               DcacheState nextstate=Idle;
+                               if(misaligned_addr || hit || hb_hit || (lb_hit && !stall_on_lb))
+                                       nextstate=Idle;
+                               else if(lb_hit && stall_on_lb || (!hit && !lb_hit &&!hb_hit))begin
+                                       nextstate=KeepPolling;
+                                       rg_poll_address<=rg_paddress;
+                               end
+                               if(nextstate==Idle)
+                                       rg_trnslte_done[0]<=False;
+                               rg_state[0]<=nextstate;
+                               `ifdef verbose $display($time,"\tDCACHE: NextState: ",fshow(nextstate)); `endif
+                               /*=====================================*/
+                               /*========= response to CPU =============*/
+                               if(rg_access_type!=Store && nextstate==Idle)
+                                       wr_response_to_cpu<= tagged Valid (tuple4(data_word,exception,0,rg_insn_epoch));// TODO perf
+                               else if(nextstate==Idle)
+                                       wr_response_to_cpu<= tagged Valid (tuple4(0,exception,0,rg_insn_epoch)); // TODO perf
+                               
+                               if(exception matches tagged None)
+                                       wbEpoch[0]<=wbEpoch[0];
+                               else
+                                       wbEpoch[0]<=~wbEpoch[0];
+                               /*=======================================*/
+                               
+                               if(rg_access_type==Store `ifdef atomic || storeResult `endif )
+                                       rg_global_dirty<=True;
+                               /*=============== updated hit buffer on a write =========*/
+                               if(hb_hit && (rg_access_type==Store `ifdef atomic || storeResult `endif ))begin
+                                       `ifdef verbose $display($time,"\tDCACHE: HB Hit. Writing Tag: %h Data: %h Way: %h",hb_tag,final_word,hb_way); `endif
+                                       hb_data.write_portA(rg_writeenable,duplicate(final_word)); 
+                               end
+                               /*============================================*/
+                               /*=============== updated line buffer on a write =========*/
+                               if(lb_hit && !stall_on_lb && (rg_access_type==Store `ifdef atomic || storeResult `endif ))begin
+                                       `ifdef verbose $display($time,"\tDCACHE: LB Hit. Writing Tag: %h Data: %h Way: %h setindex: %d",lb_tag,final_word,lb_way,lb_setindex); `endif
+                                       lb_data.write_portA(rg_writeenable,duplicate(final_word)); 
+                                       lb_dirty<=1;
+                               end
+                               if(hit && (rg_access_type==Store `ifdef atomic || storeResult `endif ) && !hb_hit)begin
+                                       `ifdef verbose $display($time,"\tDCACHE: Hit in SRAMS and writing new value :%h to HB",update_line(rg_writeenable,duplicate(final_word),dataline)); `endif
+                                       hb_tag<=cpu_tag;
+                                       hb_setindex<=setindex;
+                                       hb_data.write_portA('1,update_line(rg_writeenable,duplicate(final_word),dataline));
+                                       hb_way<=tag_hit;
+                               end
+                               if(hit && (rg_access_type==Store `ifdef atomic || storeResult `endif ) && !hb_hit)
+                                       hb_valid<=True;
+                               else if(hb_valid && !hb_hit)
+                                       hb_valid<=False;
+                               /*=============== updated SRAM entries with Hit buffer when possible =========*/
+                               if(hb_valid &&!hb_hit)begin
+                                       `ifdef verbose $display($time,"\tDCACHE: HB updating SRAM Tag: %h Data: %h Way: %h setindex: %d",hb_tag,hb_data.response_portA,hb_way,hb_setindex); `endif
+                                       wr_write_info<=tagged Valid tuple2(hb_tag,hb_setindex);
+                                       for(Integer i=0;i<`DCACHE_WAYS;i=i+1)begin      
+                                               tag[i].write_request(unpack(hb_way[i]),hb_setindex,{2'b11,hb_tag});
+                                               data[i].write_request(duplicate(hb_way[i]),hb_setindex,hb_data.response_portA);
+                                       end
+                               end
+                               /*============================================================================*/
+                               if(!hit && !lb_hit && !hb_hit && !misaligned_addr)begin// a complete miss 
+                                       `ifdef verbose $display($time,"\tDCACHE: A complete miss in Data Cache. Enquing into the memoperation FIFO"); `endif
+                                       Bit#(TLog#(`DCACHE_BLOCK_SIZE)) val1=(rg_vaddress&'hfffffff8)[word_bits+byte_bits-1:byte_bits];
+                                       Bit#(TMul#(`DCACHE_WORD_SIZE,`DCACHE_BLOCK_SIZE)) writeenable='hFF;
+                                       writeenable=writeenable<<{3'b0,val1}*8;
+                                       memoperation.enq(tuple4(cpu_tag,rg_vaddress[set_bits+word_bits+byte_bits-1:word_bits+byte_bits],replace_vec,writeenable));
+                                       ff_read_request_to_memory.enq(To_Memory {address:rg_paddress&'hfffffff8,burst_length:fromInteger(`DCACHE_BLOCK_SIZE),ld_st:Load, transfer_size:3});
+                                       if((valid_values&dirty_values&replace_vec)==replace_vec)begin // if the replacing is dirty
+                                               `ifdef verbose $display($time,"\tDCACHE: Line being replaced is dirty. Addr: %h Data: %h",write_address,replace_vec); `endif
+                                               ff_write_request_to_memory.enq(To_Memory_Write {address:write_address,burst_length:fromInteger(`DCACHE_BLOCK_SIZE),ld_st:Load, transfer_size:3,
+                                                               data_line:replace_dataline });
+                                               pending_write_response[0]<=True;
+                                       end
+                               end
+                       end
+                       else if(rg_access_type==Load || rg_access_type==Atomic)begin
+                               ff_read_request_to_memory.enq(To_Memory {address:rg_paddress,burst_length:1,ld_st:Load,transfer_size:rg_transfer_size});
+                               rg_state[0]<=IOReadResp;
+                       end
+                       else if(rg_access_type==Store)begin
+                               ff_write_request_to_memory.enq(To_Memory_Write{address:rg_paddress,data_line:zeroExtend(rg_writedata),burst_length:1,transfer_size:rg_transfer_size,ld_st:Store});
+                               rg_state[0]<=IOWriteResp;
+                       end
+                       end
+                       else if(rg_trnslte_done[0])begin
+                               rg_state[0]<=Idle;
+                               wr_response_to_cpu<= tagged Valid (tuple4(0,rg_tlb_exception[0],0,rg_insn_epoch));//TODO perf
+                               wbEpoch[0]<=~wbEpoch[0];
+                               rg_tlb_exception[0]<=tagged None;
+                               rg_perf_monitor<=0;
+                               rg_trnslte_done[0]<=False;
+                               `ifdef verbose $display($time,"\tDCACHE: Exception from TLB taken"); `endif
+                       end
+                       else begin
+                               `ifdef verbose $display($time,"\tDCACHE: Translation not done"); `endif
+                               rg_state[0] <= Idle;
+                       end
+                       /*==========================================================*/
+               endrule
+               rule wait_for_ioread_response(rg_state[0]==IOReadResp && !memoperation.notEmpty);
+                       `ifdef verbose $display($time,"\tDCACHE: Received IO Read Response"); `endif
+                       Bit#(TLog#(`DCACHE_WORD_SIZE)) byte_offset=rg_vaddress[byte_bits-1:0];
+                       Bit#(`Reg_width) data_value=ff_read_response_from_memory.first.data_line;
+                       ff_read_response_from_memory.deq;
+                       data_value=data_value>>({4'b0,byte_offset}*8);
+                       if(!rg_signextend)
+                               data_value=rg_transfer_size==0?zeroExtend(data_value[7:0]):rg_transfer_size==1?zeroExtend(data_value[15:0]):rg_transfer_size==2?zeroExtend(data_value[31:0]):data_value;
+                       else
+                               data_value=rg_transfer_size==0?signExtend(data_value[7:0]):rg_transfer_size==1?signExtend(data_value[15:0]):rg_transfer_size==2?signExtend(data_value[31:0]):data_value;
+                       wr_response_to_cpu<=tagged Valid (tuple4(data_value,ff_read_response_from_memory.first.bus_error==1?tagged Exception Load_access_fault:tagged None,rg_perf_monitor,rg_insn_epoch));
+                       wbEpoch[0]<=ff_read_response_from_memory.first.bus_error==1?~wbEpoch[0]:wbEpoch[0];
+                       `ifdef atomic
+                       if(rg_access_type==Atomic)begin
+                               let {success,storeResult,atomicdata} <- atomic_operation(data_value,rg_writedata,rg_atomic_op,rg_paddress);
+                               `ifdef MMU
+                                       ff_write_request_to_memory.enq(To_Memory_Write{address:rg_paddress,data_line:zeroExtend(atomicdata),burst_length:1,transfer_size:rg_transfer_size,ld_st:Store});
+                               `else
+                                       ff_write_request_to_memory.enq(To_Memory_Write{address:truncate(rg_vaddress),data_line:zeroExtend(new_data),burst_length:1,transfer_size:rg_transfer_size,ld_st:Store});
+                               `endif
+                               rg_state[0]<=IOWriteResp;
+                       end
+                       else
+                       `endif
+                       begin
+                               rg_state[0]<=Idle;
+                       end
+                       rg_perf_monitor<=0;
+               endrule
+               rule wait_for_iowrite_response(rg_state[0]==IOWriteResp && !memoperation.notEmpty && !pending_write_response[2]);
+                       `ifdef verbose $display($time,"\tDCACHE: Received IO Write Response"); `endif
+                       ff_write_response_from_memory.deq;
+                       if(rg_access_type!=Atomic) begin
+                               wr_response_to_cpu<=tagged Valid (tuple4(0,ff_write_response_from_memory.first.bus_error==1?tagged Exception Store_access_fault:tagged None,rg_perf_monitor,rg_insn_epoch));
+                               wbEpoch[0]<=ff_write_response_from_memory.first.bus_error==1?~wbEpoch[0]:wbEpoch[0];
+                       end
+                       rg_perf_monitor<=0;
+                       rg_state[0]<=Idle;
+               endrule
+               method Action virtual_address(Bit#(`VADDR) vaddress, Access_type load_store, Bit#(TMul#(`DCACHE_WORD_SIZE,8)) writedata, Bit#(3) transfer_size, `ifdef atomic Bit#(5) atomic_op, `endif Bool signextend, Bit#(1) insnepoch) if(rg_state[1]==Idle);
+                       if((transfer_size=='b01 && vaddress[0]!='b0) || (transfer_size=='b10 && vaddress[1:0]!=0) || (transfer_size=='b11 && vaddress[2:0]!=0))
+                               misaligned_addr<=True;
+                       else
+                               misaligned_addr<=False;
+                       Bit#(`PERFMONITORS) perf_monitor=0;
+                       Bit#(TLog#(`DCACHE_SETS)) setindex=vaddress[set_bits+word_bits+byte_bits-1:word_bits+byte_bits];
+                       `ifdef verbose $display($time,"\tDCACHE: ",fshow(load_store)," Request of VAddr: %h transfersize: %d signextend: %b setindex: %d data:%h",vaddress,transfer_size, signextend,setindex,writedata); `endif
+                       Bit#(TMul#(`DCACHE_WORD_SIZE,`DCACHE_BLOCK_SIZE)) we=transfer_size==0?'b1:transfer_size==1?'b11:transfer_size==2?'hF:'hFF;
+                       Bit#(TLog#(`DCACHE_BLOCK_SIZE)) word_offset= vaddress[word_bits+byte_bits-1:byte_bits];
+                       Bit#(TLog#(`DCACHE_WORD_SIZE)) byte_offset=vaddress[byte_bits-1:0];
+                       we=we<<{4'b0,word_offset}*8;
+                       we=we<<byte_offset;
+                       rg_access_type<=load_store;
+                       Bool proceed=True;
+                       rg_vaddress<=vaddress;
+                       rg_transfer_size<=transfer_size;
+                       `ifdef atomic rg_atomic_op<=atomic_op; `endif
+                       rg_writedata<=transfer_size==0?duplicate(writedata[7:0]):transfer_size==1?duplicate(writedata[15:0]):transfer_size==2?duplicate(writedata[31:0]):writedata;
+                       rg_writeenable<=we;
+                       rg_signextend<=signextend;
+                       rg_insn_epoch<=insnepoch;
+                       if(wr_write_info matches tagged Valid .x)begin
+                               let {newtag,newindex}=x;
+                               if(newindex==setindex)
+                                       proceed=False;
+                       end
+                       if(load_store==Fence)begin
+                               rg_state[1]<=FenceStart;
+                       end
+                       else begin
+                               if(proceed)begin
+                                       for(Integer i=0;i<`DCACHE_WAYS;i=i+1)begin // send address to the Block_rams
+                                               tag[i].read_request(setindex);
+                                               data[i].read_request(setindex);
+                                       end
+                                       rg_state[1]<=ReadingCache;
+                               end
+                               else begin
+                                       capture_counters<=True;
+                                       rg_state[1]<=Stall1;
+                               end
+                       end
+               endmethod
+               method Maybe#(Tuple4#(Bit#(`Reg_width), Trap_type,Bit#(`PERFMONITORS),Bit#(1))) response_to_core;
+                       return wr_response_to_cpu;
+               endmethod
+               `ifdef MMU
+                       method Action physical_address(Bit#(`PADDR) paddr, Trap_type exception);
+                               `ifdef verbose $display($time,"\tDCACHE: Sending physical address %h to dcache ",paddr); `endif
+                               rg_paddress<=paddr;
+                               rg_trnslte_done[1] <= True;
+                               rg_tlb_exception[1]<=exception;
+                       endmethod
+               `endif
+               method ActionValue#(To_Memory#(`PADDR)) read_request_to_memory;
+                       ff_read_request_to_memory.deq;
+                       return ff_read_request_to_memory.first;
+               endmethod
+               method ActionValue#(To_Memory_Write) write_request_to_memory;
+                       ff_write_request_to_memory.deq;
+                       return ff_write_request_to_memory.first;
+                       endmethod
+               method Bool init_complete;
+                       return (rg_state[0]!=Fence);    
+               endmethod
+               method Action read_response_from_memory(From_Memory#(`DCACHE_WORD_SIZE) resp);
+                       `ifdef verbose $display($time,"\tDCACHE: Memory has responded"); `endif
+                       ff_read_response_from_memory.enq(resp);
+               endmethod
+               method Action write_response_from_memory(From_Memory#(`DCACHE_WORD_SIZE) resp);
+                       ff_write_response_from_memory.enq(resp);
+               endmethod
+               method Action flush_from_wb;
+                       `ifdef verbose $display($time,"\tDCACHE: Inverting the wbEPOCH due to WB stage flush"); `endif
+                       wbEpoch[1]<=~wbEpoch[1];
+               endmethod
+       endmodule
+endpackage
diff --git a/src/core/dcache_asic_generic.bsv b/src/core/dcache_asic_generic.bsv
new file mode 100644 (file)
index 0000000..606e9a7
--- /dev/null
@@ -0,0 +1,652 @@
+/*
+Copyright (c) 2013, IIT Madras
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+*  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+*  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+*  Neither the name of IIT Madras  nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+*/
+package dcache_asic;
+       /*===== Pacakge imports ===== */
+       import BRAMCore::*;
+       import FIFO::*;
+       import FIFOF::*;
+       import SpecialFIFOs::*;
+       import LFSR::*;
+       import ConfigReg::*;
+       import DReg::*;
+       import BUtils::*;
+       import MemoryMap::*;
+       import mem_config1::*;
+       /*===== project imports==== */
+       import defined_types::*;
+       `include "defined_parameters.bsv"
+       import QuadMem::*;
+       /*========================= */
+
+
+       interface Ifc_dcache;
+               method Action virtual_address(Bit#(`VADDR) vaddress, Access_type load_store, Bit#(TMul#(`DCACHE_WORD_SIZE,8)) writedata, Bit#(3) transfer_size, Bit#(5) atomic_op, Bool signextend);
+               method Maybe#(Tuple3#(Bit#(`Reg_width), Trap_type,Bit#(`PERFMONITORS))) response_to_core;
+               method ActionValue#(To_Memory#(`PADDR)) read_request_to_memory;
+               method ActionValue#(To_Memory_Write) write_request_to_memory;
+               method Action read_response_from_memory(From_Memory#(`DCACHE_WORD_SIZE) resp);
+               method Action write_response_from_memory(From_Memory#(`DCACHE_WORD_SIZE) resp);
+               method Bool init_complete;
+               `ifdef MMU
+                       method Action physical_address(Bit#(`PADDR) paddr, Trap_type exception);
+               `endif
+       endinterface
+
+       typedef enum {Idle,KeepPolling,Stall1,Initialize,ReadingCache,Fence,IOReadResp,IOWriteResp} DcacheState deriving (Bits,Eq,FShow);
+
+       (*synthesize*)
+       `ifdef MMU (*conflict_free ="virtual_address, physical_address"*) `endif
+       (*preempts="virtual_address,read_from_lbdata_into_hold_reg"*)
+       (*preempts="read_data_fromcache,read_from_lbdata_into_hold_reg"*)
+       module mkdcache(Ifc_dcache);
+               /* VAddr = [tag_bits|set_bits|word_bits|byte_bits] */
+               let byte_bits=valueOf(TLog#(`DCACHE_WORD_SIZE));        // number of bits to select a byte within a word. = 2
+               let word_bits=valueOf(TLog#(`DCACHE_BLOCK_SIZE));       // number of bits to select a word within a block. = 4
+               let set_bits=valueOf(TLog#(`DCACHE_SETS));                      // number of bits to select a set from the cache. = 
+               Reg#(Maybe#(Tuple2#(Bit#(1),Bit#(`PADDR)))) rg_lr_paddress<-mkReg(tagged Invalid);
+               function ActionValue#(Tuple3#(Maybe#(Bit#(1)),Bool, Bit#(TMul#(`DCACHE_WORD_SIZE,8)))) atomic_operation(Bit#(TMul#(`DCACHE_WORD_SIZE,8)) loaded_value, Bit#(TMul#(`DCACHE_WORD_SIZE,8)) rs2, Bit#(5) atomic_op, Bit#(`PADDR) addr);
+               return (
+               actionvalue 
+                       Bit#(TMul#(`DCACHE_WORD_SIZE,8)) atomic_result=rs2;
+                       Bit#(TMul#(`DCACHE_WORD_SIZE,8)) op1;
+                       Maybe#(Bit#(1)) sc_done=tagged Invalid;
+                       if(atomic_op[4]==1)
+                               op1=signExtend(loaded_value[31:0]);
+                       else
+                               op1=loaded_value;
+                       Bit#(TMul#(`DCACHE_WORD_SIZE,8)) op2=(atomic_op[4]==1)?signExtend(rs2[31:0]):rs2;
+                       Int#(TMul#(`DCACHE_WORD_SIZE,8)) s_op1=unpack(op1);
+                       Int#(TMul#(`DCACHE_WORD_SIZE,8)) s_op2 = unpack(op2);
+                       Bool store_result = True;
+                       `ifdef verbose $display($time,"\tDCACHE: atomic instruction atomic op %b op1: %h op2: %h", atomic_op,op1,op2); `endif
+                       case (atomic_op[3:0])
+                               'b0011:atomic_result=op2;
+                               'b0000: atomic_result= (op1+op2);
+                               'b0010: atomic_result= (op1^op2);
+                               'b0110: atomic_result= (op1&op2);
+                               'b0100: atomic_result= (op1|op2);
+                               'b1100: atomic_result= min(op1,op2);
+                               'b1110: atomic_result= max(op1,op2);
+                               'b1000: atomic_result= pack(min(s_op1,s_op2));
+                               'b1010: atomic_result= pack(max(s_op1,s_op2));
+                               'b0101: action begin 
+                                                                       rg_lr_paddress <= tagged Valid tuple2(atomic_op[4],addr);
+                                                                       atomic_result=loaded_value; // LR
+                                                                       store_result = False;
+                                                               end
+                                                               endaction
+                               'b0111: begin
+                                                                       atomic_result=rs2;                        // SC
+                                                                       sc_done = tagged Valid 1;
+                                                                       store_result = False;
+                                                                       `ifdef verbose $display($time,"\tDCACHE: store condition instruction"); `endif
+                                                                       if(rg_lr_paddress matches tagged Valid .lr) begin
+                                                                               let {x,y} = lr;
+                                                                               if(x==atomic_op[4] && addr== y) begin
+                                                                                       `ifdef verbose $display($time,"\tDCACHE: store condition satisfied"); `endif
+                                                                                       sc_done = tagged Valid 0;
+                                                                                       rg_lr_paddress <= tagged Invalid;
+                                                                                       store_result = True;
+                                                                         end
+                                                                       end
+                                                               end
+                               default:                atomic_result= op1;
+                       endcase 
+                       if(atomic_op[4]==1)
+                                       atomic_result=duplicate(atomic_result[31:0]);
+
+                       return tuple3(sc_done,store_result,atomic_result);
+                       endactionvalue );
+               endfunction
+//             BRAM_DUAL_PORT#(Bit#(TLog#(`DCACHE_SETS)),Bit#(TAdd#(20,2))) tag [`DCACHE_WAYS];
+//             BRAM_DUAL_PORT_BE#(Bit#(TLog#(`DCACHE_SETS)),Bit#(TMul#(TMul#(8,`DCACHE_WORD_SIZE),`DCACHE_BLOCK_SIZE)),64) data [`DCACHE_WAYS];
+               Ifc_dcache_data data [`DCACHE_WAYS];
+               Ifc_dcache_tag   tag  [`DCACHE_WAYS];
+               for(Integer i=0;i<`DCACHE_WAYS;i=i+1)begin
+                       tag[i] <- mkdcache_tag;         
+                       data[i] <-mkdcache_data;
+               end
+               Ifc_QuadMem lbdata <-mkQuadMem;
+
+               LFSR#(Bit#(2)) random_line<-mkRCounter(3);                                                              // for random line replacement
+               /* storage for requests from the cpu */
+               Reg#(Bool) rg_global_dirty[2] <-mkCReg(2,False);
+               Reg#(Bit#(`VADDR)) rg_vaddress<-mkReg(0);
+               Reg#(Bit#(3)) rg_transfer_size<-mkReg(0);
+               Reg#(Bit#(5)) rg_atomic_op<-mkReg(0);
+               Reg#(Bit#(TMul#(`DCACHE_WORD_SIZE,8))) rg_writedata<-mkReg(0);
+               Reg#(Access_type) rg_load_store<-mkReg(Load);
+               Reg#(Bit#(TMul#(`DCACHE_WORD_SIZE,`DCACHE_BLOCK_SIZE))) rg_writeenable<-mkReg(0);
+               Reg#(Bool) rg_signextend<-mkReg(False);
+               Reg#(Bool) update_data_from_lb[2]<-mkCReg(2,False);
+               Reg#(Bool) hold_data_from_lb<-mkDReg(False);
+               Reg#(Bit#(1)) lb_dirty <-mkReg(0);
+               /*=================================== */
+               /* storage for physical translation */
+               `ifdef MMU
+               Reg#(Bit#(`PADDR)) rg_paddress<-mkReg(0);
+               Reg#(Bool)      rg_trnslte_done[2] <- mkCReg(2, `ifdef MMU False `else True `endif );
+               Reg#(Trap_type) rg_tlb_exception<-mkReg(tagged None);
+               `endif
+               /*==================================== */
+
+               Reg#(Bit#(`PERFMONITORS)) rg_perf_monitor<-mkReg(0);
+               Reg#(DcacheState) rg_state[3]<-mkCReg(3,Initialize);                            // this needs to be a CReg so that request can fire in the same cycle as response
+               Reg#(Bit#(TLog#(`DCACHE_SETS))) set_index <-mkReg(0);
+               Reg#(Bit#(TLog#(`DCACHE_WAYS))) way_index <-mkReg(0);
+               Reg#(Bit#(TMul#(`DCACHE_WORD_SIZE,`DCACHE_BLOCK_SIZE))) rg_we<-mkReg(0);
+               Reg#(Bit#(TMul#(`DCACHE_WORD_SIZE,`DCACHE_BLOCK_SIZE))) line_bytes_written<-mkReg(0);
+
+               Wire#(Maybe#(Tuple2#(Bit#(20),Bit#(TLog#(`DCACHE_SETS))))) wr_write_info<-mkDWire(tagged Invalid);      
+               Wire#(Maybe#(Tuple3#(Bit#(`Reg_width), Trap_type, Bit#(`PERFMONITORS)))) wr_response_to_cpu<-mkDWire(tagged Invalid);
+               FIFOF#(To_Memory#(`PADDR)) ff_read_request_to_memory <-mkLFIFOF();
+               FIFOF#(To_Memory_Write) ff_write_request_to_memory <-mkLFIFOF();
+               FIFOF#(From_Memory#(`DCACHE_WORD_SIZE)) ff_read_response_from_memory <-mkSizedBypassFIFOF(1);
+               FIFOF#(From_Memory#(`DCACHE_WORD_SIZE)) ff_write_response_from_memory <-mkSizedBypassFIFOF(1);
+               FIFOF#(Tuple4#(Bit#(20),Bit#(TLog#(`DCACHE_SETS)),Bit#(TLog#(`DCACHE_WAYS)),Bit#(TMul#(`DCACHE_WORD_SIZE,`DCACHE_BLOCK_SIZE)))) memoperation <-mkUGSizedFIFOF(2);
+               Reg#(Bool) increment_counters <-mkReg(True);
+               Reg#(Bool) capture_counters <-mkDReg(False);
+               Reg#(Bool) pending_fence_write_response[2]<-mkCReg(2,False);
+
+               rule display_state;
+                       `ifdef verbose $display($time,"\tDCACHE: state",fshow(rg_state[0])); `endif
+               endrule
+
+               /*====== Invalidate all the entries in the cache on startup or during Fence ==== */
+               rule fencing_the_cache(rg_state[0]==Initialize && !memoperation.notEmpty);
+                       `ifdef verbose $display($time,"\tDCACHE: Initializing index: %d",set_index," ",fshow(rg_load_store)); `endif
+                       for(Integer i=0;i<`DCACHE_WAYS;i=i+1)begin
+                               tag[i].write_request(truncate(set_index),0);
+                       end
+                       if(set_index==fromInteger(`DCACHE_SETS-1)) begin
+                               rg_state[0]<=Idle;
+                               set_index<=0;
+                               way_index<=0;
+                               random_line.seed('d3);
+                               rg_global_dirty[0]<=False;
+                               rg_trnslte_done[1]<=False;
+                               if(rg_load_store==Fence)
+                                       wr_response_to_cpu<= tagged Valid (tuple3(0,tagged None,0));
+                       end
+                       else
+                               set_index<=set_index+1;
+               endrule
+               rule deq_write_response_during_fence(pending_fence_write_response[0]);
+                       ff_write_response_from_memory.deq;
+                       pending_fence_write_response[0]<=False;
+               endrule
+               /*=============================================================================== */
+               rule handle_fence(rg_state[0]==Fence &&!memoperation.notEmpty);
+                       Bit#(20) tag_values=tag[way_index].read_response[20-1:0];       // hold the tag values
+                       Bit#(1) dirty_value=tag[way_index].read_response[20+1];         // holds the dirty bits
+                       Bit#(1) valid_value=tag[way_index].read_response[20];           // holds the dirty bits
+                       Bit#(TMul#(8,TMul#(`DCACHE_WORD_SIZE,`DCACHE_BLOCK_SIZE))) data_values; // holds the cache lines.
+                       Bit#(TAdd#(TLog#(`DCACHE_WORD_SIZE),TLog#(`DCACHE_BLOCK_SIZE))) p_offset =0;
+                       data_values=data[way_index].read_response;
+
+                       Bit#(`PADDR) write_addr={tag_values,truncate(set_index),p_offset};
+                       `ifdef verbose $display($time,"\tDCACHE: Handling Fence.tag %h setindex: %d way_index: %d Dirty: %b Valid: %b",tag_values,set_index,way_index,dirty_value,valid_value); `endif
+                       `ifdef verbose $display($time,"\tDCACHE: Fence addr: %h line: %h ",write_addr,data_values); `endif 
+                       Bit#(TLog#(`DCACHE_SETS)) new_set=set_index;
+                       Bit#(TLog#(`DCACHE_SETS)) old_set=set_index;
+                       if(!pending_fence_write_response[1])begin
+                               if(dirty_value==1 && valid_value==1)begin // valid and dirty
+                                       ff_write_request_to_memory.enq(To_Memory_Write { // send the request to memory to 
+                        address:write_addr,  data_line:data_values,
+                                                       burst_length:`DCACHE_BLOCK_SIZE,  transfer_size:3, ld_st:Store});
+                                       pending_fence_write_response[1]<=True;
+                               end
+                               if(way_index==fromInteger(`DCACHE_WAYS-1))begin
+                                       new_set=set_index+1;
+                                       if(set_index==fromInteger(`DCACHE_SETS-1))begin
+                                               rg_state[0]<=Idle;
+                                               rg_global_dirty[0]<=False;
+                                               wr_response_to_cpu<= tagged Valid (tuple3(0,tagged None,0));
+                                               rg_trnslte_done[1]<=False;
+                                               set_index<=0;
+                                       end
+                                       else
+                                               set_index<=new_set;
+                               end
+                               way_index<=way_index+1;
+                       end
+                       tag[way_index+1].read_request(new_set);
+                       tag[way_index].write_request(old_set,0);
+                       data[way_index+1].read_request(new_set);
+                       
+               endrule
+
+               (*conflict_free="virtual_address,read_data_fromcache"*)
+               rule read_data_fromcache(rg_state[0]==ReadingCache && memoperation.notFull);
+                       /*========== Check for hit or miss =================== */
+                       Bit#(TLog#(`DCACHE_WAYS)) linenum=0;
+                       Bit#(`PERFMONITORS) perf_monitor=rg_perf_monitor;
+                       Bit#(TMul#(TMul#(`DCACHE_BLOCK_SIZE,`DCACHE_WORD_SIZE),8)) dataline=0;
+                       Bool hit=False;
+                       Bool lbhit=False;
+                       Bit#(`DCACHE_WAYS) valid_values=0;              // hold the valid and dirty bits
+                       Bit#(`DCACHE_WAYS) dirty_values=0;              // hold the valid and dirty bits
+                       Bit#(TLog#(`DCACHE_BLOCK_SIZE)) word_offset=rg_vaddress[word_bits+byte_bits-1:byte_bits];
+                       Bit#(TLog#(`DCACHE_WORD_SIZE)) byte_offset=rg_vaddress[byte_bits-1:0];
+                       Bit#(TLog#(`DCACHE_SETS)) setindex=rg_vaddress[set_bits+word_bits+byte_bits-1:word_bits+byte_bits];
+                       Bit#(TLog#(`DCACHE_WAYS)) replaceblock=0;
+                       `ifdef MMU
+                               Bit#(20) cpu_tag=rg_paddress[`PADDR-1:`PADDR-20];
+                       `else
+                               Bit#(20) cpu_tag=rg_vaddress[`PADDR-1:`PADDR-20];
+                       `endif
+                       `ifdef MMU
+                       if(increment_counters)begin
+                               if(rg_load_store==Load)
+                                       perf_monitor[`TOTAL_LOADS]=1;
+                               else if(rg_load_store==Store)
+                                       perf_monitor[`TOTAL_STORES]=1;
+                               else 
+                                       perf_monitor[`TOTAL_ATOMIC]=1;
+                       end
+                       if(rg_trnslte_done[0] &&& rg_tlb_exception matches tagged None) begin
+                               if(!is_IO_Addr(rg_paddress))begin
+                       `else
+                               if(!is_IO_Addr(truncate(rg_vaddress)))begin
+                       `endif
+                                       if(increment_counters)begin
+                                               if(rg_load_store==Load)
+                                                       perf_monitor[`DCACHE_CACHEABLE_LOAD]=1;
+                                               else if(rg_load_store==Store)
+                                                       perf_monitor[`DCACHE_CACHEABLE_STORE]=1;
+                                               else if(rg_load_store==Atomic)
+                                                       perf_monitor[`DCACHE_CACHEABLE_ATOMIC]=1;
+                                       end
+                                       else
+                                               increment_counters<=True;
+
+                                       valid_values={tag[3].read_response[20],tag[2].read_response[20],tag[1].read_response[20],tag[0].read_response[20]};
+                                       dirty_values={tag[3].read_response[21],tag[2].read_response[21],tag[1].read_response[21],tag[0].read_response[21]};
+                                               
+                                       for(Integer i=0;i<`DCACHE_WAYS;i=i+1)begin
+                                               let stored_tag=tag[i].read_response[19:0];
+                                               let stored_valid=tag[i].read_response[20];
+                                               if(valid_values[i]==0)
+                                                       replaceblock=fromInteger(i);
+                                               if(stored_valid==1 && stored_tag==cpu_tag)begin // if a tag matches capture the tag and data
+                                                       hit=True;       
+                                                       linenum=fromInteger(i);
+                                                       dataline=data[i].read_response;
+                                               end
+                                       end
+                                       let linebuffer=lbdata.response_portA;   
+                                       let {lbtag,lbset,lbreplaceblock,lbwriteenable}=memoperation.first;
+                                       if(memoperation.notEmpty && lbset==setindex && lbtag==cpu_tag)begin
+                                               dataline=linebuffer;
+                                               lbhit=True;
+                                       end
+                                       `ifdef verbose $display($time,"DCACHE: DATALINE: %h",dataline); `endif
+                                       Bit#(`Reg_width) data_value=(dataline>>{6'd0,word_offset}*64)[`Reg_width-1:0];
+                                       data_value=data_value>>({4'b0,byte_offset}*8);
+                                       if(!rg_signextend)
+                                               data_value=rg_transfer_size==0?zeroExtend(data_value[7:0]):rg_transfer_size==1?zeroExtend(data_value[15:0]):rg_transfer_size==2?zeroExtend(data_value[31:0]):data_value;
+                                       else
+                                               data_value=rg_transfer_size==0?signExtend(data_value[7:0]):rg_transfer_size==1?signExtend(data_value[15:0]):rg_transfer_size==2?signExtend(data_value[31:0]):data_value;
+
+                                       /*====================================================== */
+                                       /*=========== Respond to Core ============================ */
+                                       if((rg_transfer_size=='b01 && rg_vaddress[0]!='b0) || (rg_transfer_size=='b10 && rg_vaddress[1:0]!=0) || (rg_transfer_size=='b11 && rg_vaddress[2:0]!=0))begin // miss-aligned error.
+                                               perf_monitor[`DCACHE_MISALIGNED]=1; // cache mis-aligned error.
+                                               if(rg_load_store==Load)
+                                                       wr_response_to_cpu<= tagged Valid (tuple3(0,tagged Exception Load_addr_misaligned,perf_monitor));
+                                               else 
+                                                       wr_response_to_cpu<=tagged Valid (tuple3(0,tagged Exception Store_addr_misaligned,perf_monitor));
+                                               rg_state[0]<=Idle;
+                                               rg_perf_monitor<=0;
+                                               `ifdef MMU rg_trnslte_done[0] <= False; `endif
+                                       end
+                                       else if(hit||lbhit)begin // if there has been a hit.
+                                               let {success,storeResult,newdata} <- atomic_operation(data_value,rg_writedata,rg_atomic_op,rg_paddress);
+                                               if(rg_load_store==Load)
+                                                       storeResult=False;
+                                               if(success matches tagged Valid .sc)
+                                                       data_value = zeroExtend(sc);
+                                               if(lbhit && (line_bytes_written & rg_writeenable) != rg_writeenable)begin
+                                                       rg_state[0]<=KeepPolling;
+                                                       rg_perf_monitor<=perf_monitor;
+                                               `ifdef verbose  $display($time,"\tDCACHE: Going to poll LB: %h we: %h",line_bytes_written,rg_writeenable); `endif
+                                               end
+                                               else begin      
+                                                       if(rg_load_store==Store)
+                                                               data_value=0;
+                                                       `ifdef verbose $display($time,"\tDCACHE: Hit for ",fshow(rg_load_store)," address : %h data: %h line: %d rg_writedata: %h rg_writeenable: %h lbhit: %b atomic_data %h storeResult %b",rg_vaddress,data_value,linenum,rg_writedata,rg_writeenable, lbhit, newdata, storeResult); `endif
+                                                       wr_response_to_cpu<=tagged Valid (tuple3(data_value,tagged None,perf_monitor));
+                                                       rg_trnslte_done[0] <= False;
+                                                       rg_perf_monitor<=0;
+                                                       rg_state[0]<=Idle;
+                                                       if(rg_load_store==Store || storeResult)begin //Atomic but not LR
+                                                               `ifdef verbose $display("Store or atomic kuch toh ho raha hai"); `endif
+                                                               wr_write_info<=tagged Valid tuple2(cpu_tag,setindex);
+                                                               if(lbhit)begin
+                                                                       if(rg_load_store==Store)
+                                                                               lbdata.write_portA(rg_writeenable,duplicate(rg_writedata));
+                                                                       else
+                                                                               lbdata.write_portA(rg_writeenable,duplicate(newdata));
+                                                                       `ifdef verbose if(line_bytes_written!='1)
+                                                                               $display("WRITING ON BOTH PORTS OF LB"); `endif
+                                                                       lb_dirty<=1;
+                                                               end
+                                                               else begin
+                                                                       tag[linenum].write_request(rg_vaddress[set_bits+word_bits+byte_bits-1:word_bits+byte_bits],{2'b11,tag[linenum].read_response[19:0]});
+                                                                       if(rg_load_store==Store)
+                                                                               data[linenum].write_request(rg_writeenable,rg_vaddress[set_bits+word_bits+byte_bits-1:word_bits+byte_bits],duplicate(rg_writedata));
+                                                                       else
+                                                                               data[linenum].write_request(rg_writeenable,rg_vaddress[set_bits+word_bits+byte_bits-1:word_bits+byte_bits],duplicate(newdata));
+                                                               end
+                                                               rg_global_dirty[0]<=True;
+                                                       end
+                                               end
+                                       end
+                                       /*====================================================== */
+                                       /*==== Request to memory =============================== */
+                                       else begin // miss
+                                               rg_state[0]<=KeepPolling;
+                                               if(rg_load_store==Load)
+                                                       perf_monitor[`DCACHE_LOAD_MISS]=1;
+                                               else if(rg_load_store==Store)
+                                                       perf_monitor[`DCACHE_STORE_MISS]=1;
+                                               else if(rg_load_store==Atomic)
+                                                       perf_monitor[`DCACHE_ATOMIC_MISS]=1;
+
+                                               if(valid_values=='1)begin // if all the lines are valid and no match then replace line
+                                                       perf_monitor[`DCACHE_LINEREPLACE]=1; // cache line replacement increment.
+                                                       if(dirty_values[0]==0)
+                                                               replaceblock=0;
+                                                       else if(dirty_values[1]==0)
+                                                               replaceblock=1;
+                                                       else if(dirty_values[2]==0)
+                                                               replaceblock=2;
+                                                       else if(dirty_values[3]==0)
+                                                               replaceblock=3;
+                                                       else begin
+                                                               replaceblock=truncate(random_line.value);
+                                                               random_line.next;
+                                                       end
+                                                       `ifdef verbose $display($time,"\tDCACHE: Miss of ",fshow(rg_load_store)," address: %h Replacing line: %d valid: %b dirty_values: %b",rg_vaddress,replaceblock,valid_values,dirty_values); `endif
+                                               end
+                                               else begin
+                                                       `ifdef verbose $display($time,"\tDCACHE: Miss of ",fshow(rg_load_store)," address: %h Filling line: %d",rg_vaddress,replaceblock); `endif
+                                               end
+                                               if(memoperation.notEmpty && lbset==setindex && replaceblock==lbreplaceblock)begin
+                                                       replaceblock=replaceblock+1;
+                                               end
+                                                       
+                                               `ifdef MMU
+                                                       ff_read_request_to_memory.enq(To_Memory {address:rg_paddress&'hfffffff8,burst_length:fromInteger(`DCACHE_BLOCK_SIZE),ld_st:Load, transfer_size:3});
+                                               `else
+                                                       ff_read_request_to_memory.enq(To_Memory {address:truncate(rg_vaddress&'hfffffff8),burst_length:fromInteger(`DCACHE_BLOCK_SIZE),ld_st:Load, transfer_size:3});
+                                               `endif
+                                               Bit#(TLog#(`DCACHE_BLOCK_SIZE)) val1=(rg_vaddress&'hfffffff8)[word_bits+byte_bits-1:byte_bits];
+                                               Bit#(TMul#(`DCACHE_WORD_SIZE,`DCACHE_BLOCK_SIZE)) writeenable='hFF;
+                                               writeenable=writeenable<<{3'b0,val1}*8;
+                                               if(dirty_values[replaceblock]==1)begin // if the replacing is dirty
+                                                       perf_monitor[`DCACHE_WRITEBACKS]=1;
+                                                       Bit#(TAdd#(TLog#(`DCACHE_WORD_SIZE),TLog#(`DCACHE_BLOCK_SIZE))) offset_zeros='d0;
+                                                       Bit#(`PADDR) write_address={tag[replaceblock].read_response[20-1:0],setindex[6:0],offset_zeros};
+                                                       `ifdef verbose $display($time,"\tDCACHE: Line being replaced is dirty. Addr: %h Data: %h",write_address,data[replaceblock].read_response); `endif
+                                                       ff_write_request_to_memory.enq(To_Memory_Write {address:write_address,burst_length:fromInteger(`DCACHE_BLOCK_SIZE),ld_st:Load, transfer_size:3,
+                                                                       data_line:data[replaceblock].read_response });
+                                                               pending_fence_write_response[0]<=True;
+                                               end
+                                               memoperation.enq(tuple4(cpu_tag,rg_vaddress[set_bits+word_bits+byte_bits-1:word_bits+byte_bits],replaceblock,writeenable));
+                                               `ifdef verbose $display($time,"\tDCACHE: mask: %h byteoffset: %h",writeenable,val1); `endif
+                                               rg_perf_monitor<=perf_monitor;
+                                       end
+                               end
+                               else begin
+                                       if(rg_load_store==Load || rg_load_store==Atomic)begin
+                                               `ifdef MMU
+                                                       ff_read_request_to_memory.enq(To_Memory {address:rg_paddress,burst_length:1,ld_st:Load,transfer_size:rg_transfer_size});
+                                               `else
+                                                       ff_read_request_to_memory.enq(To_Memory {address:truncate(rg_vaddress),burst_length:1,ld_st:Load,transfer_size:rg_transfer_size});
+                                               `endif
+                                               rg_state[0]<=IOReadResp;
+                                       end
+                                       else if(rg_load_store==Store)begin
+                                               `ifdef verbose $display($time,"\tDCACHE: Sending IO Write REQUEST"); `endif
+                                               `ifdef MMU
+                                                       ff_write_request_to_memory.enq(To_Memory_Write{address:rg_paddress,data_line:zeroExtend(rg_writedata),burst_length:1,transfer_size:rg_transfer_size,ld_st:Store});
+                                               `else
+                                                       ff_write_request_to_memory.enq(To_Memory_Write{address:truncate(rg_vaddress),data_line:zeroExtend(rg_writedata),burst_length:1,transfer_size:rg_transfer_size,ld_st:Store});
+                                               `endif
+                                               rg_state[0]<=IOWriteResp;
+                                       end
+                               end
+                       `ifdef MMU
+                       end
+                       else if(rg_trnslte_done[0])begin
+                               rg_state[0]<=Idle;
+                               wr_response_to_cpu<= tagged Valid (tuple3(0,rg_tlb_exception,perf_monitor));
+                               rg_tlb_exception<=tagged None;
+                               rg_perf_monitor<=0;
+                               rg_trnslte_done[0]<=False;
+                               $display($time,"\tDCACHE: Exception from TLB taken");
+                       end
+                       else begin
+                               $display($time,"\tDCACHE: Translation not done");
+                               rg_state[0] <= Idle;
+                       end
+                       `endif
+               endrule
+               rule wait_for_ioread_response(rg_state[0]==IOReadResp && memoperation.notFull);
+                       `ifdef verbose $display($time,"\tDCACHE: Received IO Read Response"); `endif
+                       Bit#(TLog#(`DCACHE_WORD_SIZE)) byte_offset=rg_vaddress[byte_bits-1:0];
+                       Bit#(`Reg_width) data_value=ff_read_response_from_memory.first.data_line;
+                       ff_read_response_from_memory.deq;
+                       data_value=data_value>>({4'b0,byte_offset}*8);
+                       if(!rg_signextend)
+                               data_value=rg_transfer_size==0?zeroExtend(data_value[7:0]):rg_transfer_size==1?zeroExtend(data_value[15:0]):rg_transfer_size==2?zeroExtend(data_value[31:0]):data_value;
+                       else
+                               data_value=rg_transfer_size==0?signExtend(data_value[7:0]):rg_transfer_size==1?signExtend(data_value[15:0]):rg_transfer_size==2?signExtend(data_value[31:0]):data_value;
+                       wr_response_to_cpu<=tagged Valid (tuple3(data_value,ff_read_response_from_memory.first.bus_error==1?tagged Exception Load_access_fault:tagged None,rg_perf_monitor));
+                       if(rg_load_store==Atomic)begin
+                               let {success,storeResult,newdata} <- atomic_operation(data_value,rg_writedata,rg_atomic_op,rg_paddress);
+                               `ifdef MMU
+                                       ff_write_request_to_memory.enq(To_Memory_Write{address:rg_paddress,data_line:zeroExtend(newdata),burst_length:1,transfer_size:rg_transfer_size,ld_st:Store});
+                               `else
+                                       ff_write_request_to_memory.enq(To_Memory_Write{address:truncate(rg_vaddress),data_line:zeroExtend(new_data),burst_length:1,transfer_size:rg_transfer_size,ld_st:Store});
+                               `endif
+                               rg_state[0]<=IOWriteResp;
+                       end
+                       else begin
+                               rg_state[0]<=Idle;
+                       end
+                       rg_perf_monitor<=0;
+               endrule
+               rule wait_for_iowrite_response(rg_state[0]==IOWriteResp && !memoperation.notEmpty && !pending_fence_write_response[1]);
+                       `ifdef verbose $display($time,"\tDCACHE: Received IO Write Response"); `endif
+                       ff_write_response_from_memory.deq;
+                       if(rg_load_store!=Atomic)
+                               wr_response_to_cpu<=tagged Valid (tuple3(0,ff_write_response_from_memory.first.bus_error==1?tagged Exception Store_access_fault:tagged None,rg_perf_monitor));
+                       rg_perf_monitor<=0;
+                       rg_state[0]<=Idle;
+               endrule
+               /*============== One cycle delay to ensure the write is reflected in the BRAM ========= */
+               rule stall_the_next_request_by_one_cycle(rg_state[0]==Stall1);
+                       Bit#(TLog#(`DCACHE_SETS)) setindex=rg_vaddress[set_bits+word_bits+byte_bits-1:word_bits+byte_bits];
+                       for(Integer i=0;i<`DCACHE_WAYS;i=i+1)begin // send address to the Block_rams
+                               tag[i].read_request(setindex);
+                               data[i].read_request(setindex);
+                       end
+                       rg_state[0]<=ReadingCache;
+               endrule
+               /*===================================================================================== */
+               /*======= filling up the cache from the data recieved from the external memory ======= */
+               (*conflict_free="virtual_address,fillcache"*)
+               rule fillcache(memoperation.notEmpty && line_bytes_written!='1);
+                       let memresp=ff_read_response_from_memory.first;
+                       ff_read_response_from_memory.deq;
+                       let {cpu_tag,setindex,replaceblock,writeenable}=memoperation.first;
+                       `ifdef verbose $display($time,"\tDCACHE: Response from Memory: %h setindex: %d cpu_tag: %h replaceblock: %d",memresp.data_line,setindex,cpu_tag,replaceblock); `endif 
+                       let we=writeenable;
+                       if(|line_bytes_written!=0)begin
+                               we=rg_we;
+                       end
+                       Bit#(TMul#(2,TMul#(`DCACHE_WORD_SIZE,`DCACHE_BLOCK_SIZE))) extended_mask=zeroExtend(we)<<8;
+                       lbdata.write_portB(we,duplicate(memresp.data_line));
+                       `ifdef verbose $display($time,"\tDCACHE: linebytes: %h currently writing into: %h",line_bytes_written,we); `endif
+                       if(memresp.last_word)begin // if all the data words have been fetched exit      
+                               `ifdef verbose $display($time,"\tDCACHE: Received Last response from Memory set: %d ",setindex); `endif
+                       end
+                       line_bytes_written<=line_bytes_written|we;
+                       rg_we<=extended_mask[2*`DCACHE_BLOCK_SIZE*`DCACHE_WORD_SIZE-1:`DCACHE_BLOCK_SIZE*`DCACHE_WORD_SIZE]|extended_mask[`DCACHE_BLOCK_SIZE*`DCACHE_WORD_SIZE-1:0];
+               endrule
+               rule read_from_lbdata_into_hold_reg(line_bytes_written=='1);
+                       let lb_hold_reg=lbdata.response_portB;
+                       let {cputag,setindex,replaceblock,writeenable}=memoperation.first;
+                       data[replaceblock].write_request('1,setindex,lb_hold_reg);
+                       tag[replaceblock].write_request(setindex,{lb_dirty,1'b1,cputag});
+                       line_bytes_written<=0;
+                       lb_dirty<=0;
+                       memoperation.deq;
+                       `ifdef verbose $display($time,"\tDCACHE: capturing lbdata cpu_tag: %h setindex: %d addr: %h linenum: %d data: %h",cputag, setindex,{cputag,setindex,6'd0}, replaceblock,lb_hold_reg); `endif
+                       if(rg_state[1]==ReadingCache)
+                               rg_state[1]<=Stall1;
+               endrule
+               /*===================================================================================== */
+               /*===================================================================================== */
+               rule keep_polling_on_stall(rg_state[0]==KeepPolling);
+                       Bit#(`PERFMONITORS) perf_monitor=rg_perf_monitor;
+                       if(capture_counters)begin
+                               $display($time,"\tDCACHE: Miss during polling for ",fshow(rg_load_store));
+                               if(rg_load_store==Load)begin
+                                       perf_monitor[`DCACHE_LOAD_MISS]=1;
+                                       perf_monitor[`DCACHE_CACHEABLE_LOAD]=1;
+                               end
+                               else if(rg_load_store==Store)begin
+                                       perf_monitor[`DCACHE_STORE_MISS]=1;
+                                       perf_monitor[`DCACHE_CACHEABLE_STORE]=1;
+                               end
+                               else if(rg_load_store==Atomic) begin
+                                       perf_monitor[`DCACHE_ATOMIC_MISS]=1;
+                                       perf_monitor[`DCACHE_CACHEABLE_ATOMIC]=1;
+                               end
+                               rg_perf_monitor<=perf_monitor;
+                       end
+                               
+                       Bit#(TLog#(`DCACHE_SETS)) setindex=rg_vaddress[set_bits+word_bits+byte_bits-1:word_bits+byte_bits];
+                       `ifdef MMU
+                               Bit#(20) cpu_tag=rg_paddress[`PADDR-1:`PADDR-20];
+                       `else
+                               Bit#(20) cpu_tag=rg_vaddress[`PADDR-1:`PADDR-20];
+                       `endif
+                       let {lbtag,lbset,lbreplaceblock,lbwriteenable}=memoperation.first;
+                       if((line_bytes_written & rg_writeenable) == rg_writeenable && (lbset==setindex && lbtag==cpu_tag))begin
+                               `ifdef verbose $display($time,"\tDCACHE: Accessing LB"); `endif
+                               rg_state[0]<=ReadingCache; 
+                               increment_counters<=False;
+                               for(Integer i=0;i<`DCACHE_WAYS;i=i+1)begin // send address to the Block_rams
+                                       tag[i].read_request(setindex);
+                                       data[i].read_request(setindex);
+                               end
+                       end
+                       `ifdef verbose $display($time,"\tDCACHE: Polling on LB. cpu_tag: %h lbtag: %h required: %h bytes in Buffer: %h",cpu_tag,lbtag,rg_writeenable,line_bytes_written); `endif
+               endrule
+
+               /*============= Prediction in burst mode ================================ */
+               method Action virtual_address(Bit#(`VADDR) vaddress, Access_type load_store, Bit#(TMul#(`DCACHE_WORD_SIZE,8)) writedata, Bit#(3) transfer_size, Bit#(5) atomic_op, Bool signextend)if(rg_state[1]==Idle);
+                       Bit#(`PERFMONITORS) perf_monitor=0;
+                       Bit#(TLog#(`DCACHE_SETS)) setindex=vaddress[set_bits+word_bits+byte_bits-1:word_bits+byte_bits];
+                       `ifdef verbose $display($time,"\tDCACHE: ",fshow(load_store)," Request of VAddr: %h transfersize: %d signextend: %b setindex: %d",vaddress,transfer_size, signextend,setindex); `endif
+                       Bit#(TMul#(`DCACHE_WORD_SIZE,`DCACHE_BLOCK_SIZE)) we=transfer_size==0?'b1:transfer_size==1?'b11:transfer_size==2?'hF:'hFF;
+                       Bit#(TLog#(`DCACHE_BLOCK_SIZE)) word_offset= vaddress[word_bits+byte_bits-1:byte_bits];
+                       Bit#(TLog#(`DCACHE_WORD_SIZE)) byte_offset=vaddress[byte_bits-1:0];
+                       we=we<<{4'b0,word_offset}*8;
+                       we=we<<byte_offset;
+                       rg_load_store<=load_store;
+                       Bool proceed=True;
+                       if(wr_write_info matches tagged Valid .x)begin
+                               let {newtag,newindex}=x;
+                               if(newindex==setindex && load_store!=Store)
+                                       proceed=False;
+                       end
+                       if(load_store==Fence)begin
+                               if(!rg_global_dirty[1])begin
+                                       rg_state[1]<=Initialize;
+                               end
+                               else begin
+                                       tag[0].read_request(0);
+                                       data[0].read_request(0);
+                                       rg_state[1]<=Fence;
+                               end
+                       end
+                       else begin
+                               rg_vaddress<=vaddress;
+                               rg_transfer_size<=transfer_size;
+                               rg_atomic_op<=atomic_op;
+                               rg_writedata<=transfer_size==0?duplicate(writedata[7:0]):transfer_size==1?duplicate(writedata[15:0]):transfer_size==2?duplicate(writedata[31:0]):writedata;
+                               rg_writeenable<=we;
+                               rg_signextend<=signextend;
+                               if(proceed)begin
+                                       for(Integer i=0;i<`DCACHE_WAYS;i=i+1)begin // send address to the Block_rams
+                                               tag[i].read_request(setindex);
+                                               data[i].read_request(setindex);
+                                       end
+                                       rg_state[1]<=ReadingCache;
+                               end
+                               else begin
+                                       capture_counters<=True;
+                                       rg_state[1]<=Stall1;
+                               end
+                       end
+               endmethod
+               method Maybe#(Tuple3#(Bit#(`Reg_width), Trap_type,Bit#(`PERFMONITORS))) response_to_core;
+                       return wr_response_to_cpu;
+               endmethod
+               `ifdef MMU
+                       method Action physical_address(Bit#(`PADDR) paddr, Trap_type exception);
+                               `ifdef verbose $display($time,"\tDCACHE: Sending physical address %h to icache ",paddr); `endif
+                               rg_paddress<=paddr;
+                               rg_trnslte_done[1] <= True;
+                               rg_tlb_exception<=exception;
+                       endmethod
+               `endif
+               method ActionValue#(To_Memory#(`PADDR)) read_request_to_memory;
+                       ff_read_request_to_memory.deq;
+                       return ff_read_request_to_memory.first;
+               endmethod
+               method ActionValue#(To_Memory_Write) write_request_to_memory;
+                       ff_write_request_to_memory.deq;
+                       return ff_write_request_to_memory.first;
+                       endmethod
+               method Bool init_complete;
+                       return (rg_state[1]!=Fence);    
+               endmethod
+               method Action read_response_from_memory(From_Memory#(`DCACHE_WORD_SIZE) resp);
+                       `ifdef verbose $display($time,"\tDCACHE: Memory has responded"); `endif
+                       ff_read_response_from_memory.enq(resp);
+               endmethod
+               method Action write_response_from_memory(From_Memory#(`DCACHE_WORD_SIZE) resp);
+                       ff_write_response_from_memory.enq(resp);
+               endmethod
+
+       endmodule
+
+       module mkTb(Empty);
+               Ifc_dcache dcache<-mkdcache;
+               rule send_request;
+                       dcache.virtual_address('d4,Load,'h01234567ABCDEF89,'d2,'d0,False);
+               endrule
+               rule terminate;
+                       let x<-$stime;
+                       if(x>10)
+                               $finish(0);
+               endrule
+       endmodule
+endpackage
diff --git a/src/core/decode.defines b/src/core/decode.defines
new file mode 100644 (file)
index 0000000..3fd0971
--- /dev/null
@@ -0,0 +1,204 @@
+       `define FNADD  0
+       `define FNSL    1
+       `define FNLR    2
+       `define FNSEQ   2
+       `define FNSC   3
+       `define FNSNE   3
+       `define FNXOR   4
+       `define FNSR    5
+       `define FNOR    6
+       `define FNAND   7
+       `define FNSUB   10
+       `define FNSRA   11
+       `define FNSLT   12
+       `define FNSGE   13
+       `define FNSLTU  14
+       `define FNSGEU  15
+
+       `define FNSWAP 1 
+       `define FMINU   10
+       `define FMIN    11
+       `define FMAXU  12
+       `define FMAX    13
+       
+       `define FNRAND  8
+
+       `define BEQ                'b?????????????????000?????1100011
+       `define BNE                'b?????????????????001?????1100011
+       `define BLT                'b?????????????????100?????1100011
+       `define BGE                'b?????????????????101?????1100011
+       `define BLTU               'b?????????????????110?????1100011
+       `define BGEU               'b?????????????????111?????1100011
+       `define JALR               'b?????????????????000?????1100111
+       `define JAL                'b?????????????????????????1101111
+       `define LUI                'b?????????????????????????0110111
+       `define AUIPC              'b?????????????????????????0010111
+       `define ADDI               'b?????????????????000?????0010011
+       `define SLLI               'b000000???????????001?????0010011
+       `define SLTI               'b?????????????????010?????0010011
+       `define SLTIU              'b?????????????????011?????0010011
+       `define XORI               'b?????????????????100?????0010011
+       `define SRLI               'b000000???????????101?????0010011
+       `define SRAI               'b010000???????????101?????0010011
+       `define ORI                'b?????????????????110?????0010011
+       `define ANDI               'b?????????????????111?????0010011
+       `define ADD                'b0000000??????????000?????0110011
+       `define SUB                'b0100000??????????000?????0110011
+       `define SLL                'b0000000??????????001?????0110011
+       `define SLT                'b0000000??????????010?????0110011
+       `define SLTU               'b0000000??????????011?????0110011
+       `define XOR                'b0000000??????????100?????0110011
+       `define SRL                'b0000000??????????101?????0110011
+       `define SRA                'b0100000??????????101?????0110011
+       `define OR                 'b0000000??????????110?????0110011
+       `define AND                'b0000000??????????111?????0110011
+       `define ADDIW              'b?????????????????000?????0011011
+       `define SLLIW              'b0000000??????????001?????0011011
+       `define SRLIW              'b0000000??????????101?????0011011
+       `define SRAIW              'b0100000??????????101?????0011011
+       `define ADDW               'b0000000??????????000?????0111011
+       `define SUBW               'b0100000??????????000?????0111011
+       `define SLLW               'b0000000??????????001?????0111011
+       `define SRLW               'b0000000??????????101?????0111011
+       `define SRAW               'b0100000??????????101?????0111011
+       `define LB                 'b?????????????????000?????0000011
+       `define LH                 'b?????????????????001?????0000011
+       `define LW                 'b?????????????????010?????0000011
+       `define LD                 'b?????????????????011?????0000011
+       `define LBU                'b?????????????????100?????0000011
+       `define LHU                'b?????????????????101?????0000011
+       `define LWU                'b?????????????????110?????0000011
+       `define SB                 'b?????????????????000?????0100011
+       `define SH                 'b?????????????????001?????0100011
+       `define SW                 'b?????????????????010?????0100011
+       `define SD                 'b?????????????????011?????0100011
+       `define FENCE              'b?????????????????000?????0001111
+       `define FENCE_I            'b?????????????????001?????0001111
+       `define MUL                'b0000001??????????000?????0110011
+       `define MULH               'b0000001??????????001?????0110011
+       `define MULHSU             'b0000001??????????010?????0110011
+       `define MULHU              'b0000001??????????011?????0110011
+       `define DIV                'b0000001??????????100?????0110011
+       `define DIVU               'b0000001??????????101?????0110011
+       `define REM                'b0000001??????????110?????0110011
+       `define REMU               'b0000001??????????111?????0110011
+       `define MULW               'b0000001??????????000?????0111011
+       `define DIVW               'b0000001??????????100?????0111011
+       `define DIVUW              'b0000001??????????101?????0111011
+       `define REMW               'b0000001??????????110?????0111011
+       `define REMUW              'b0000001??????????111?????0111011
+       `define AMOADD_W           'b00000????????????010?????0101111
+       `define AMOXOR_W           'b00100????????????010?????0101111
+       `define AMOOR_W            'b01000????????????010?????0101111
+       `define AMOAND_W           'b01100????????????010?????0101111
+       `define AMOMIN_W           'b10000????????????010?????0101111
+       `define AMOMAX_W           'b10100????????????010?????0101111
+       `define AMOMINU_W          'b11000????????????010?????0101111
+       `define AMOMAXU_W          'b11100????????????010?????0101111
+       `define AMOSWAP_W          'b00001????????????010?????0101111
+       `define LR_W               'b00010??00000?????010?????0101111
+       `define SC_W               'b00011????????????010?????0101111
+       `define AMOADD_D           'b00000????????????011?????0101111
+       `define AMOXOR_D           'b00100????????????011?????0101111
+       `define AMOOR_D            'b01000????????????011?????0101111
+       `define AMOAND_D           'b01100????????????011?????0101111
+       `define AMOMIN_D           'b10000????????????011?????0101111
+       `define AMOMAX_D           'b10100????????????011?????0101111
+       `define AMOMINU_D          'b11000????????????011?????0101111
+       `define AMOMAXU_D          'b11100????????????011?????0101111
+       `define AMOSWAP_D          'b00001????????????011?????0101111
+       `define LR_D               'b00010??00000?????011?????0101111
+       `define SC_D               'b00011????????????011?????0101111
+       `define ECALL              'b00000000000000000000000001110011
+       `define EBREAK             'b00000000000100000000000001110011
+       `define URET               'b00000000001000000000000001110011
+       `define SRET               'b00010000001000000000000001110011
+       `define HRET               'b00100000001000000000000001110011
+       `define MRET               'b00110000001000000000000001110011
+       `define DRET               'b01111011001000000000000001110011
+       `define SFENCE_VMA         'b0001001??????????000000001110011
+       `define WFI                'b00010000010100000000000001110011
+       `define CSRRW              'b?????????????????001?????1110011
+       `define CSRRS              'b?????????????????010?????1110011
+       `define CSRRC              'b?????????????????011?????1110011
+       `define CSRRWI             'b?????????????????101?????1110011
+       `define CSRRSI             'b?????????????????110?????1110011
+       `define CSRRCI             'b?????????????????111?????1110011
+       `define FADD_S             'b0000000??????????????????1010011
+       `define FSUB_S             'b0000100??????????????????1010011
+       `define FMUL_S             'b0001000??????????????????1010011
+       `define FDIV_S             'b0001100??????????????????1010011
+       `define FSGNJ_S            'b0010000??????????000?????1010011
+       `define FSGNJN_S           'b0010000??????????001?????1010011
+       `define FSGNJX_S           'b0010000??????????010?????1010011
+       `define FMIN_S             'b0010100??????????000?????1010011
+       `define FMAX_S             'b0010100??????????001?????1010011
+       `define FSQRT_S            'b010110000000?????????????1010011
+       `define FADD_D             'b0000001??????????????????1010011
+       `define FSUB_D             'b0000101??????????????????1010011
+       `define FMUL_D             'b0001001??????????????????1010011
+       `define FDIV_D             'b0001101??????????????????1010011
+       `define FSGNJ_D            'b0010001??????????000?????1010011
+       `define FSGNJN_D           'b0010001??????????001?????1010011
+       `define FSGNJX_D           'b0010001??????????010?????1010011
+       `define FMIN_D             'b0010101??????????000?????1010011
+       `define FMAX_D             'b0010101??????????001?????1010011
+       `define FCVT_S_D           'b010000000001?????????????1010011
+       `define FCVT_D_S           'b010000100000?????????????1010011
+       `define FSQRT_D            'b010110100000?????????????1010011
+       `define FLE_S              'b1010000??????????000?????1010011
+       `define FLT_S              'b1010000??????????001?????1010011
+       `define FEQ_S              'b1010000??????????010?????1010011
+       `define FLE_D              'b1010001??????????000?????1010011
+       `define FLT_D              'b1010001??????????001?????1010011
+       `define FEQ_D              'b1010001??????????010?????1010011
+       `define FCVT_W_S           'b110000000000?????????????1010011
+       `define FCVT_WU_S          'b110000000001?????????????1010011
+       `define FCVT_L_S           'b110000000010?????????????1010011
+       `define FCVT_LU_S          'b110000000011?????????????1010011
+       `define FMV_X_S            'b111000000000?????000?????1010011
+       `define FCLASS_S           'b111000000000?????001?????1010011
+       `define FCVT_W_D           'b110000100000?????????????1010011
+       `define FCVT_WU_D          'b110000100001?????????????1010011
+       `define FCVT_L_D           'b110000100010?????????????1010011
+       `define FCVT_LU_D          'b110000100011?????????????1010011
+       `define FMV_X_D            'b111000100000?????000?????1010011
+       `define FCLASS_D           'b111000100000?????001?????1010011
+       `define FCVT_S_W           'b110100000000?????????????1010011
+       `define FCVT_S_WU          'b110100000001?????????????1010011
+       `define FCVT_S_L           'b110100000010?????????????1010011
+       `define FCVT_S_LU          'b110100000011?????????????1010011
+       `define FMV_S_X            'b111100000000?????000?????1010011
+       `define FCVT_D_W           'b110100100000?????????????1010011
+       `define FCVT_D_WU          'b110100100001?????????????1010011
+       `define FCVT_D_L           'b110100100010?????????????1010011
+       `define FCVT_D_LU          'b110100100011?????????????1010011
+       `define FMV_D_X            'b111100100000?????000?????1010011
+       `define FLW                'b?????????????????010?????0000111
+       `define FLD                'b?????????????????011?????0000111
+       `define FSW                'b?????????????????010?????0100111
+       `define FSD                'b?????????????????011?????0100111
+       `define FMADD_S            'b?????00??????????????????1000011
+       `define FMSUB_S            'b?????00??????????????????1000111
+       `define FNMSUB_S           'b?????00??????????????????1001011
+       `define FNMADD_S           'b?????00??????????????????1001111
+       `define FMADD_D            'b?????01??????????????????1000011
+       `define FMSUB_D            'b?????01??????????????????1000111
+       `define FNMSUB_D           'b?????01??????????????????1001011
+       `define FNMADD_D           'b?????01??????????????????1001111
+       `define FRFLAGS            'b00000000000100000010?????1110011
+       `define FSFLAGS            'b000000000001?????001?????1110011
+       `define FSFLAGSI           'b000000000001?????101?????1110011
+       `define FRRM               'b00000000001000000010?????1110011
+       `define FSRM               'b000000000010?????001?????1110011
+       `define FSRMI              'b000000000010?????101?????1110011
+       `define FSCSR              'b000000000011?????001?????1110011
+       `define FRCSR              'b00000000001100000010?????1110011
+       `define RDCYCLE            'b11000000000000000010?????1110011
+       `define RDTIME             'b11000000000100000010?????1110011
+       `define RDINSTRET          'b11000000001000000010?????1110011
+       `define RDCYCLEH           'b11001000000000000010?????1110011
+       `define RDTIMEH            'b11001000000100000010?????1110011
+       `define RDINSTRETH         'b11001000001000000010?????1110011
+       `define SCALL              'b00000000000000000000000001110011
+       `define SBREAK             'b00000000000100000000000001110011
diff --git a/src/core/decode_opfetch.bsv b/src/core/decode_opfetch.bsv
new file mode 100644 (file)
index 0000000..39f50ec
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+Copyright (c) 2013, IIT Madras
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+*  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+*  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+*  Neither the name of IIT Madras  nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+*/
+package decode_opfetch;
+       /*============= package imports ========== */
+       import FIFOF::*;
+       import TxRx:: *;
+       import DReg::*;
+       /* ======================================= */
+
+       /* ============== project imports ======= */
+       import registerfile::*;
+       import decoder::*;
+       import defined_types::*;
+       `include "defined_parameters.bsv"
+       /* ======================================= */
+
+       interface Ifc_decode_opfetch;
+               method Action write_rd (Bit#(5)r, Bit#(`Reg_width) d, Operand_type rdtype);
+               /* ====================== pipe connections ========= */
+               interface RXe#(IF_ID_type) rx_in;
+               interface TXe#(ID_IE_type) tx_out;
+               /*================================================== */
+               `ifdef Debug
+                       method Bit#(`Reg_width)                 read_debug_igpr (Bit#(5) r);                             // Read a General-Purpose Register
+                       method Action write_debug_igpr (Bit#(5) r, Bit#(`Reg_width) d);                          // Write a General-Purpose Register
+                       method Bit#(`Reg_width)                 read_debug_fgpr (Bit#(5) r);                             // Read a General-Purpose Register
+                       method Action write_debug_fgpr (Bit#(5) r, Bit#(`Reg_width) d);                          // Write a General-Purpose Register
+               `endif
+               method Action flush();
+               method Action trap_from_csr(Tuple2#(Bit#(3),Trap_type) tt);
+               method Action misa(Bit#(`Reg_width) val);
+               method Action update_eEpoch;
+               method Action update_wEpoch;
+    method Action inferred_xlen(Bit#(2) mxl);
+       endinterface:Ifc_decode_opfetch
+
+               function Bool isNone(Trap_type trap);
+                       if(trap matches tagged None)
+                               return True;
+                       else 
+                               return False;
+               endfunction
+
+       (*synthesize*)
+       module mkdecode_opfetch(Ifc_decode_opfetch);
+               Reg#(Bit#(`PERFMONITORS)) rg_decode_perfmon<-mkDReg(0);
+               Wire#(Tuple2#(Bit#(3),Trap_type)) wr_trap_type<-mkDWire(tuple2(0,tagged None));
+               Wire#(Bit#(`Reg_width)) wr_misa<-mkWire();
+               Reg#(Bit#(1)) eEpoch <-mkReg(0);
+               Reg#(Bit#(1)) wEpoch <-mkReg(0);
+               // this is used to ensure that when a trap is 
+               // taken no other instruction fills the pipe unless wb generates a flush. Stores are avoided using this mechanism
+               Reg#(Bool) rg_flush_ahead <-mkReg(False); 
+                                                                                                                               
+
+               Ifc_registerfile registerfile <-mkregisterfile();
+               RX#(IF_ID_type) rx <-mkRX;
+               TX#(ID_IE_type) tx <-mkTX;
+               /*=================================== Decode and Operand Fetch ======================================================================*/
+    // This rule decodes the instruction and provides necessary info for the execution units.
+               rule rl_operand_fetch(rx.u.notEmpty && tx.u.notFull && !rg_flush_ahead);
+                       `ifdef verbose
+                               $display($time,"\t********** DECODE STAGE FIRING ************ PC: %h EPOCHS: %b Instr-EPOCHS: %b",rx.u.first.program_counter,{eEpoch,wEpoch}, rx.u.first.epochs)  ;
+                       `endif
+                       if({eEpoch,wEpoch}!=rx.u.first.epochs)begin
+                               `ifdef verbose $display($time,"\tDECODE: PC: %h Dropping Instruction since EPOCSH do not match",rx.u.first.program_counter); `endif
+                               rx.u.deq();
+                       end
+                       else begin
+                               let x = fn_decode(rx.u.first().instruction,rx.u.first.exception, wr_misa, rx.u.first.perfmonitors);
+                               let pc=rx.u.first.program_counter;
+                               let dest=x.rd;
+                               let {debugcause,csr_ex}=wr_trap_type;   
+                               Bit#(`PERFMONITORS) perfmonitor_incr=x.perf;
+                               Trap_type exception=x.exception;
+                Bool trap_on_wfi = False;
+                               if(exception matches tagged None) 
+                                       exception = csr_ex;
+                               Bool dnwfi=True;
+                if(x.immediate_value[2:0]=='b101 && x.immediate_value[5]==0 && x.funct3==0 && x.inst_type==SYSTEM_INSTR) begin
+                                       dnwfi=False;
+                    trap_on_wfi = True;
+                end
+                               if(exception matches tagged Interrupt .i) 
+                                       dnwfi=True;
+
+                if(trap_on_wfi && dnwfi)
+                    pc=pc+4;
+
+                               Bit#(`VADDR) nextpc=rx.u.first.nextpc;
+
+                               if(x.inst_type==NOP)begin
+                                       `ifdef verbose $display($time,"DECODE: NOP Instruction"); `endif
+                                       rx.u.deq();     
+                               end
+                               else begin
+                                       Bool choose_rs3=`ifdef spfpu ( `ifdef dpfpu x.inst_type==DFLOATING || `endif x.inst_type==FLOATING) && (rx.u.first.instruction[6:4]=='b100) `else False `endif ;
+                                       let operands<- registerfile._inputs_from_decode_stage(x.rs1,x.rs1type,x.rs2,x.rs2type,pc,x.immediate_value  `ifdef spfpu ,choose_rs3, x.rs3 `endif );
+                                       if(dnwfi)begin
+                                               Bool e = isNone(exception);
+                                               if(!e || x.inst_type==SYSTEM_INSTR)
+                                                       rg_flush_ahead<=True;
+                                               rx.u.deq();
+                                               tx.u.enq(ID_IE_type{
+                                                       rs1:operands.rs1,
+                                                       rs2:(x.inst_type==MEMORY && (x.mem_access!=Load))?x.immediate_value:operands.rs2,
+                                                       rs3_imm:`ifdef spfpu (choose_rs3)?operands.rs3: `endif (x.inst_type==MEMORY && x.mem_access!=Load)?operands.rs2:x.immediate_value,
+                                                       rdtype:x.rdtype,
+                                                       inst_type:x.inst_type,
+                                                       destination:x.rd,
+                                                       program_counter:pc,
+                                                       exception:exception,
+                                                       fn:x.fn,
+                                                       mem_access:x.mem_access,
+                                                       word32:x.word32,
+                                                       funct3:x.funct3,
+                                                       nextpc:rx.u.first.nextpc,
+                                                       debugcause:debugcause,
+                                                       perfmonitors:perfmonitor_incr,
+                                                       prediction:rx.u.first.prediction,
+                                                       epochs:rx.u.first.epochs,
+                                                       rs1_type:x.rs1type,
+                                                       rs2_type:(x.inst_type==MEMORY && (x.mem_access!=Load))?Immediate:x.rs2type,
+                                                       rs3_type:(x.inst_type==MEMORY && (x.mem_access!=Load))?x.rs2type:`ifdef spfpu choose_rs3?FloatingRF: `endif Immediate,
+                                                       rs1addr:x.rs1,
+                                                       rs2addr:x.rs2,
+                                                       rs3addr:(x.inst_type==MEMORY && (x.mem_access!=Load))?x.rs2:choose_rs3?x.rs3:0
+                                                       `ifdef simulate ,instruction:rx.u.first.instruction `endif });
+                                       end
+                                       else begin
+                                               `ifdef verbose $display($time,"\tWaiting for interrupt"); `endif
+                                       end
+                                       `ifdef verbose
+                                       $display($time,"\tDECODE:       Instruction : %h",rx.u.first().instruction," ",fshow(x.inst_type)," FN: %b",x.fn," ",fshow(x.mem_access)); 
+                                       $display($time,"\tRs1: %d",x.rs1," ",fshow(x.rs1type));
+                                       $display($time,"\tRs2: %d",x.rs2," ",fshow(x.rs2type)); 
+                                       `ifdef spfpu   $display($time,"\tRs3: %d",x.rs3); `endif
+                                       $display($time,"\tRd: %d",x.rd," ",fshow(x.rdtype)); 
+                                       $display($time,"\tImmediate Value: %h",x.immediate_value); 
+                                       $display($time,"\tException: ",fshow(exception)); 
+                                       $display($time,"\t*****************************************************");
+                                       `endif
+                               end
+                       end
+          endrule
+               /* ============================== method and interface definitions ========================= */
+               method tx_out=tx.e;
+               method rx_in=rx.e;
+               method Action write_rd (Bit#(5)r, Bit#(`Reg_width) d, Operand_type rdtype)=registerfile.write_rd(r,d,rdtype);
+               method Action flush();
+                       `ifdef verbose $display($time,"\tDECODE: Flushing"); `endif
+                       rg_flush_ahead<=False;
+               endmethod
+               method Action trap_from_csr(Tuple2#(Bit#(3),Trap_type) tt);
+                       wr_trap_type<=tt;
+               endmethod
+               `ifdef Debug
+                       method read_debug_igpr (Bit#(5) r) = registerfile.read_debug_igpr(r);                            // Read a General-Purpose Register
+                       method Action write_debug_igpr (Bit#(5) r, Bit#(`Reg_width) d)=registerfile.write_debug_igpr(r,d);                               // Write a General-Purpose Register
+                       method read_debug_fgpr (Bit#(5) r)=registerfile.read_debug_fgpr(r);                              // Read a General-Purpose Register
+                       method Action write_debug_fgpr (Bit#(5) r, Bit#(`Reg_width) d)=registerfile.write_debug_fgpr(r,d);                               // Write a General-Purpose Register
+               `endif
+               method Action misa(Bit#(`Reg_width) val);
+                       wr_misa<=val;
+               endmethod
+               method Action update_eEpoch;
+                       `ifdef verbose $display($time,"\tDECODE: updating eEpoch"); `endif
+                       eEpoch<=~eEpoch;
+               endmethod
+               method Action update_wEpoch;
+                       `ifdef verbose $display($time,"\tDECODE: updating wEpoch"); `endif
+                       wEpoch<=~wEpoch;
+               endmethod
+    method Action inferred_xlen(Bit#(2) mxl) ;
+      registerfile.inferred_xlen(mxl);
+    endmethod
+//             method init_complete=registerfile.init_complete;
+       endmodule
+endpackage:decode_opfetch
diff --git a/src/core/decoder.bsv b/src/core/decoder.bsv
new file mode 100644 (file)
index 0000000..902b409
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+Copyright (c) 2013, IIT Madras
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+*  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+*  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+*  Neither the name of IIT Madras  nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+*/
+package decoder; 
+   `include "defined_parameters.bsv" 
+   import defined_types::*; 
+   typedef struct { 
+      Bit#(4) fn;  
+      Bit#(5) rs1;  
+      Bit#(5) rs2;  
+      Bit#(5) rs3;  
+      Bit#(5) rd;  
+      Operand_type rs1type;  
+      Operand_type rs2type; 
+      Operand_type rdtype; 
+      Instruction_type inst_type; 
+      Bit#(`Reg_width) immediate_value; 
+      Bool word32; 
+      Access_type mem_access;    
+      Trap_type exception; 
+      Bit#(3) funct3; 
+      Bit#(`PERFMONITORS) perf;  
+      } Decoded_data deriving(Bits,Eq,FShow); 
+(*noinline*) 
+function Decoded_data fn_decode(Bit#(32) instruction, Trap_type exception, Bit#(`Reg_width) misa, Bit#(`PERFMONITORS) perfmonitors); 
+   Bit#(5) rs1=instruction[19:15]; 
+   Bit#(5) rs2=instruction[24:20]; 
+   Bit#(5) rs3=instruction[31:27]; 
+   Bit#(5) rd=instruction[11:7]; 
+   Bit#(5) opcode = instruction[6:2]; 
+    Bit#(7) funct7 = instruction[31:25]; 
+   Bit#(3) funct3 = instruction[14:12]; 
+   Bool word32 =False; 
+   Access_type mem_access=Load; 
+       `ifdef atomic
+          if(opcode[3]=='b1 && opcode[1]=='b1) 
+                  mem_access=Atomic; 
+               else 
+       `endif
+       if(opcode[3]=='b1 && opcode[1]==0) 
+      mem_access=Store; 
+   Operand_type rs1type=IntegerRF; 
+   Operand_type rs2type=IntegerRF; 
+   Operand_type rdtype=IntegerRF; 
+    
+   Bit#(`Reg_width) immediate_value=signExtend(instruction[31:20]); 
+   if(opcode==`LUI_op|| opcode==`AUIPC_op) 
+      immediate_value=signExtend({instruction[31:12],12'd0}); 
+   else if(opcode==`JAL_op) 
+      immediate_value=signExtend({instruction[31],instruction[19:12],instruction[20],instruction[30:21],1'b0}); 
+   else if(opcode==`JALR_op) 
+      immediate_value=signExtend({instruction[31:21],1'b0}); 
+   else if (opcode==`BRANCH_op) // Branch instructions 
+      immediate_value=signExtend({instruction[31],instruction[7],instruction[30:25],instruction[11:8],1'b0}); 
+   else if (opcode==`STORE_op `ifdef spfpu || opcode==`FSTORE_op `endif ) // Store operations 
+      immediate_value=signExtend({instruction[31:25],instruction[11:7]}); 
+   else if(opcode==`CSR_op) 
+      immediate_value[16:12]=instruction[19:15]; 
+       else if(opcode==`ATOMIC_op)
+               immediate_value=0;
+   if(opcode==`LUI_op || opcode==`JAL_op || opcode==`AUIPC_op || (opcode==`CSR_op && funct3[2]==1)) 
+      rs1=0; 
+   if(opcode==`CSR_op || opcode[4:2]=='b000                           // CSR or ( (F)Load or FENCE ) 
+      || opcode==`LUI_op || opcode==`JAL_op || opcode[4:2]=='b001      // LUI or JAL or (AUIPC or IMMediate Arith) 
+      || opcode==`JALR_op || (opcode[4:2]=='b101 && funct7[5]==1))   // JALR or Floating conversion operations. 
+      rs2=0; 
+   if(opcode==`BRANCH_op || opcode[4:1]=='b0100) 
+      rd=0; 
+   if(opcode==`JAL_op || opcode==`AUIPC_op) 
+      rs1type=PC; 
+`ifdef spfpu
+          else if(opcode[4:2]=='b100 || (opcode[4:2]=='b101 &&               // (F(N)MADD or F(N)SUB)  
+                  (funct7[6:3]!='b1101 && funct7[6:3]!='b1111)))                  // some of the conversion operations 
+                       rs1type=FloatingRF; 
+`endif
+   if(opcode==`JAL_op || opcode==`JALR_op || opcode==`LUI_op|| opcode[4:2]=='b001 // JAL or JALR or (AUIPC or IMM Arith) 
+      || opcode[4:1]==0)                                                // (F)Load or  
+      rs2type=Immediate; 
+`ifdef spfpu
+   else if((opcode[4:2]=='b101 && funct7[5]!='b1) || opcode==`FSTORE_op || opcode[4:2]=='b100)                  // All convert + FSQRToperations do not need rs2 
+          rs2type=FloatingRF; 
+   if(opcode==`FLOAD_op || (opcode[4:2]=='b101 &&  
+         funct7[6:3]!='b1010 && funct7[6:3]!='b1100 && funct7[6:3]!='b1110 ) || opcode[4:2]=='b100) 
+      rdtype=FloatingRF; 
+`endif
+    
+   if(opcode==`IMM_ARITHW_op || opcode==`MULDIVW_op || opcode==`ARITHW_op || (opcode[4:3]=='b10 && funct7[0]==0) 
+         || (opcode[4:1]=='b0101 && funct3[0]==0)) 
+      word32=True; 
+    
+   Instruction_type inst_type=NOP; 
+       `ifdef spfpu
+   if(opcode[4:3]=='b10)begin 
+      inst_type=funct7[0]==0?FLOATING:DFLOATING; 
+   end 
+   else `endif
+       if(opcode[4:3]=='b11)begin 
+      case (opcode[2:0]) 
+         'b011:inst_type=JAL; 
+         'b001:inst_type=JALR; 
+         'b000:inst_type=BRANCH; 
+         'b100:inst_type=SYSTEM_INSTR; 
+      endcase 
+   end 
+   else if(opcode[4:3]=='b01)begin 
+      case (opcode[2:0])  
+         'b000,'b011,'b001:inst_type=MEMORY; // STORE or FSTORE or ATOMIC 
+         'b101:inst_type=ALU;      // LUI 
+         'b100,'b110:inst_type=(funct7[0]==1)?(funct3[2]==0)?MUL:DIV:ALU; 
+      endcase 
+   end 
+   else if(opcode[4:3]=='b00)begin 
+      case(opcode[2:0]) 
+         'b000,'b001:inst_type=MEMORY;   // 
+         'b101,'b100,'b110:inst_type=ALU;      //AUIPC IMM WORD 
+         'b011:inst_type=(funct3[0]==0)?FENCE:FENCEI; 
+      endcase 
+   end 
+    
+   Trap_type ex=tagged None; 
+   if(exception matches tagged None)begin 
+      if( `ifdef spfpu (inst_type==FLOATING && misa[5]==0) `ifdef dpfpu || (inst_type==DFLOATING && misa[3]==0)  `endif || `endif
+          (inst_type==MUL && misa[12]==0)    || (inst_type==DIV && misa[12]==0) 
+            `ifdef atomic || (inst_type==MEMORY && mem_access==Atomic && misa[0]==0) `endif ) 
+         ex=tagged Exception Illegal_inst; 
+       `ifdef simulate
+               if(inst_type==JAL && immediate_value==0)
+                       ex=tagged Exception Endsimulation;
+       `endif
+               if(instruction[1:0]!='b11)
+                       ex=tagged Exception Illegal_inst;
+               if(inst_type==NOP)
+                       ex=tagged Exception Illegal_inst;
+   end 
+       else 
+          ex=exception; 
+               
+               Bit#(4) fn=0;
+               if(opcode==`ATOMIC_op)begin
+                       if((instruction[27] | instruction[28]) == 1)
+                               fn={instruction[29:27],1'b1};
+                       else
+                               fn={instruction[31:29],instruction[27]};        
+               end
+               else if(opcode==`BRANCH_op)begin
+                       if(funct3[2]==0)
+                               fn={2'b0,1,funct3[0]};
+                       else
+                               fn={1'b1,funct3};
+               end
+               else if(opcode==`JAL_op || opcode==`JALR_op || opcode==`LOAD_op `ifdef spfpu || opcode==`FLOAD_op `endif
+                               || opcode==`STORE_op `ifdef spfpu || opcode==`FSTORE_op `endif || opcode==`AUIPC_op || opcode==`LUI_op)
+                       fn=0;
+               else if(opcode==`IMM_ARITHW_op || opcode==`IMM_ARITH_op)begin
+                       fn=case(funct3)
+                               'b010: 'b1100;
+                               'b011: 'b1110;
+                               'b101: if(funct7[5]==1) 'b1011; else 'b0101;
+                               default:{1'b0,funct3};
+                       endcase;
+               end
+               else if(opcode==`ARITHW_op || opcode==`ARITH_op)begin
+                       fn=case(funct3)
+                               'b000:if(funct7[5]==1) 'b1010; else 'b0000;
+                               'b010:'b1100;
+                               'b011:'b1110;
+                               'b101:if (funct7[5]==1) 'b1011;else 'b0101;
+                               default:{1'b0,funct3};
+                       endcase;
+               end
+               else if(opcode[4:3]=='b10)
+                       fn=opcode[3:0];
+       if(inst_type==BRANCH)
+               perfmonitors[`COND_BRANCH]=1;
+       `ifdef spfpu
+               if(inst_type==FLOATING)
+                       perfmonitors[`SPFPU_INST]=1;
+       `endif
+       `ifdef dpfpu
+       if(inst_type==DFLOATING)
+               perfmonitors[`DPFPU_INST]=1;
+       `endif
+       if(inst_type==JAL || inst_type==JALR)
+               perfmonitors[`UNCOND_JUMPS]=1;
+       if(inst_type==MEMORY)
+               perfmonitors[`MEMORY_INSTRUCTIONS]=1;
+       if(inst_type==MUL || inst_type==DIV)
+               perfmonitors[`MULDIV_INSTRUCTIONS]=1;
+    
+   return (Decoded_data{fn:fn,rs1:rs1,rs2:rs2,rs3:rs3,rd:rd, 
+                        rs1type:rs1type,rs2type:rs2type,rdtype:rdtype, 
+                        inst_type:inst_type,immediate_value:immediate_value, 
+                        word32:word32,mem_access:mem_access,exception:ex, 
+                        funct3:funct3,perf:perfmonitors}); 
+                       
+endfunction        
+endpackage        
diff --git a/src/core/defined_parameters.bsv b/src/core/defined_parameters.bsv
new file mode 100644 (file)
index 0000000..c44bae3
--- /dev/null
@@ -0,0 +1,485 @@
+`define RegFileSize 32 // describes the size of ht register file in the processor.
+`ifdef spfpu
+       `define FLEN 32
+`endif
+`ifdef dpfpu
+       `define FLEN 64
+`endif
+//`define fpu_hierarchical //Define this if you want hierarchical modules in verilog
+
+//`define MMU
+`define PRFDEPTH 6
+`define USERSPACE 0
+`ifdef RV64
+       `define Burst_length_bits 8
+       `define byte_offset 2
+       `define Reg_width 64 // the register data width of the processor.
+       `define ADDR 64 // the address width
+       `define DCACHE_ADDR 64
+       `define DCACHE_BLOCK_SIZE 4
+       `define DCACHE_WORD_SIZE 8
+/////////////////////////////MMU parameters///////////////////////////////////
+`define VADDR  39      
+`define PADDR   32
+`define OFFSET 12
+`define ASID           8
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+       // TLM2 Request Response definitions for Processor to Bus connection
+       `define TLM_PRM_CPU_REQ 4, 64, 64, 5, Bit #(0)
+       `define TLM_PRM_CPU_RSP 4, 64, 64, 5, Bit #(0)
+
+       // TLM2 Request Response definitions for Memory to Bus connection
+       `define TLM_PRM_MEM_REQ 4, 64, 64, 5, Bit #(0)
+       `define TLM_PRM_MEM_RSP 4, 64, 64, 5, Bit #(0)
+
+       // Axi Request Response definitions for Processor as a Master
+       `define AXI_PRM_CPU     4, 64, 64, 5, Bit #(0)  // Fabric Interface
+       `define AXI_XTR_CPU TLMRequest #(`TLM_PRM_CPU_REQ), TLMResponse #(`TLM_PRM_CPU_RSP), `AXI_PRM_CPU // Transactor Interface
+
+       // Axi Request Response definitions for Memory as a Slave
+       `define AXI_PRM_MEM     4, 64, 64, 5, Bit #(0)  // Fabric Interface
+       `define AXI_XTR_MEM TLMRequest #(`TLM_PRM_MEM_REQ), TLMResponse #(`TLM_PRM_MEM_RSP), `AXI_PRM_MEM // Transactor Interface
+///////////////////////////////////////////////////////////////////////////////
+`else
+       `define byte_offset 1
+       `define Reg_width 32 // the register data width of the processor.
+       `define Addr_width 32 // the address width
+       `define DCACHE_ADDR 32
+       `define DCACHE_BLOCK_SIZE 8
+       `define DCACHE_WORD_SIZE 4
+///////////////////////////////////////////////////////////////////////////////
+       // TLM2 Request Response definitions for Processor to Bus connection
+       `define TLM_PRM_CPU_REQ 4, 32, 32, 5, Bit #(0)
+       `define TLM_PRM_CPU_RSP 4, 32, 32, 5, Bit #(0)
+
+       // TLM2 Request Response definitions for Memory to Bus connection
+       `define TLM_PRM_MEM_REQ 4, 32, 32, 5, Bit #(0)
+       `define TLM_PRM_MEM_RSP 4, 32, 32, 5, Bit #(0)
+
+       // Axi Request Response definitions for Processor as a Master
+       `define AXI_PRM_CPU     4, 32, 32, 5, Bit #(0)  // Fabric Interface
+       `define AXI_XTR_CPU TLMRequest #(`TLM_PRM_CPU_REQ), TLMResponse #(`TLM_PRM_CPU_RSP), `AXI_PRM_CPU // Transactor Interface
+
+       // Axi Request Response definitions for Memory as a Slave
+       `define AXI_PRM_MEM     4, 32, 32, 5, Bit #(0)  // Fabric Interface
+       `define AXI_XTR_MEM TLMRequest #(`TLM_PRM_MEM_REQ), TLMResponse #(`TLM_PRM_MEM_RSP), `AXI_PRM_MEM // Transactor Interface
+///////////////////////////////////////////////////////////////////////////////
+`endif
+
+`define Loop 1
+`define BAUD_RATE 130
+`ifdef verilog
+       `define Addr_space 22   //since we are leaving off the lower 2 bits of address(byte addressable memory), we have to 
+`else
+       `define Addr_space 30
+`endif
+`ifdef simulate
+  `define BAUD_RATE 5 //130 //
+`endif
+`define INTERRUPT_PINS 64 
+
+// Branch_predictor_paramters
+/////////////////////////// CACHE RELATED PARAMETERS ////////////////////////////////
+`define DCACHE_WAYS 4
+`define DCACHE_SETS 512
+
+`define ICACHE_WAYS 4                  // way_bits =2
+`define ICACHE_BLOCK_SIZE 8    // word_bits = 3
+`define ICACHE_SETS 512                        // set_bits     =7
+`define ICACHE_WORD_SIZE 4             // byte_bits=2
+`define ICACHE_TAG_BITS 20             // tag_bits = 52
+`define DCACHE_TAG_BITS 20             // tag_bits = 52
+`define BTB_DEPTH                      256
+`define RAS_DEPTH                      8
+/////////////////////////////////////////////////////////////////////////////////////
+`ifdef RV64
+       `define MISA_BITS   'h141129 //'h082C849//// 'h40101121 // A + F + I + M + U 
+       `define MXL_BITS                'h2
+`else
+       `define MISA_BITS   'h082C849 // 'h40101121 // A + F + I + M + U 
+       `define MXL_BITS                'h1
+`endif
+`define MTVEC_DEFAULT       'h00000000
+`define STVEC_DEFAULT       'h00000000
+`define UTVEC_DEFAULT       'h00000000
+/////////////////////////// Register Mapping for Machine Mode Regs /////////////////
+`define MSTATUS                        'h00 //'h300 // Machine Status register                                
+`define MISA                           'h01 //'h301 // ISA and extensions                                     
+`define MEDELEG                        'h02 //'h302 // Machine exception delegation                               
+`define MIDELEG                        'h03 //'h303 // Machine interrupt delegation                               
+`define MIE                                    'h04 //'h304 // Machine interrupt enable                                   
+`define MTVEC                          'h05 //'h305 // Machine trap-handler base address                          
+`define MCOUNTEREN             'h06 //'h306 // Machine counter setup register                                  
+`define MHPMEVENTSTART 'h23 //'h323 // statr of event selectors
+`define MHPMEVENTEND           'h26 //'h326 // end of event selectors
+`define MSCRATCH                       'h40 //'h340 // Scratch rgister for machine trap hanglers                  
+`define MEPC                           'h41 //'h341 // Machine exception program counter                          
+`define MCAUSE                         'h42 //'h342 // Machine trap cause                                         
+`define MTVAL                          'h43 //'h343 // Machine bad address                                        
+`define MIP                                    'h44 //'h344 // Machine interrupt pending
+`define MPOWERCONTROL  'h45 //'h345 // 2 bits to control the power switches.
+`define PMPCFG0          &nb