From: rahulb Date: Mon, 30 Jul 2018 10:58:36 +0000 (+0530) Subject: PLIC modified to support interrupts upto 1024 X-Git-Url: https://git.libre-soc.org/?p=shakti-peripherals.git;a=commitdiff_plain;h=df9621ad270f10a2f59262cb5d6c5898fd50bbf4 PLIC modified to support interrupts upto 1024 --- diff --git a/src/peripherals/plic/encoder.bsv b/src/peripherals/plic/encoder.bsv new file mode 100644 index 0000000..4a26491 --- /dev/null +++ b/src/peripherals/plic/encoder.bsv @@ -0,0 +1,131 @@ +package encoder; + +import Vector ::* ; +`define INPUT 1024 +`define OUTPUT 10 +interface Ifc_encoder#(numeric type irpins); + method Bit#(TLog#(irpins)) encode(Bit#(irpins) ip); +endinterface + +module mkencoder(Ifc_encoder#(irpins)) + provisos(Log#(irpins, irid), + Add#(a__, irpins, `INPUT), + Add#(b__, irid, `OUTPUT)); + function Bit#(irid) fn_encoder(Bit#(irpins) irp); + Bit#(`INPUT) ip = zeroExtend(irp); + Bit#(`OUTPUT) result=0; + Vector#(TDiv#(`INPUT,2),Bit#(1)) ip1; + Vector#(TDiv#(`INPUT,4),Bit#(1)) ip2; + Vector#(TDiv#(`INPUT,8),Bit#(1)) ip3; + Vector#(TDiv#(`INPUT,16),Bit#(1)) ip4; + Vector#(TDiv#(`INPUT,32),Bit#(1)) ip5; + Vector#(TDiv#(`INPUT,64),Bit#(1)) ip6; + Vector#(TDiv#(`INPUT,128),Bit#(1)) ip7; + Vector#(TDiv#(`INPUT,256),Bit#(1)) ip8; + Vector#(TDiv#(`INPUT,512),Bit#(1)) ip9; + Vector#(TDiv#(`INPUT,2),Bit#(1)) pp1; + Vector#(TDiv#(`INPUT,4),Bit#(1)) pp2; + Vector#(TDiv#(`INPUT,8),Bit#(1)) pp3; + Vector#(TDiv#(`INPUT,16),Bit#(1)) pp4; + Vector#(TDiv#(`INPUT,32),Bit#(1)) pp5; + Vector#(TDiv#(`INPUT,64),Bit#(1)) pp6; + Vector#(TDiv#(`INPUT,128),Bit#(1)) pp7; + Vector#(TDiv#(`INPUT,256),Bit#(1)) pp8; + Vector#(TDiv#(`INPUT,512),Bit#(1)) pp9; + Bit#(1) ip10; + Bit#(1) pp10; + + for(Integer i=0;i<`INPUT/2;i=i+1) begin + ip1[i]=ip[i*2+1] | ip[i*2]; + end + for(Integer i=0;i<`INPUT/4;i=i+1) begin + ip2[i]=ip1[i*2+1] | ip1[i*2]; + end + for(Integer i=0;i<`INPUT/8;i=i+1) begin + ip3[i]=ip2[i*2+1] | ip2[i*2]; + end + for(Integer i=0;i<`INPUT/16;i=i+1) begin + ip4[i]=ip3[i*2+1] | ip3[i*2]; + end + for(Integer i=0;i<`INPUT/32;i=i+1) begin + ip5[i]=ip4[i*2+1] | ip4[i*2]; + end + for(Integer i=0;i<`INPUT/64;i=i+1) begin + ip6[i]=ip5[i*2+1] | ip5[i*2]; + end + for(Integer i=0;i<`INPUT/128;i=i+1) begin + ip7[i]=ip6[i*2+1] | ip6[i*2]; + end + for(Integer i=0;i<`INPUT/256;i=i+1) begin + ip8[i]=ip7[i*2+1] | ip7[i*2]; + end + for(Integer i=0;i<`INPUT/512;i=i+1) begin + ip9[i]=ip8[i*2+1] | ip8[i*2]; + end + + for(Integer i=0;i<`INPUT/2;i=i+1) begin + pp1[i]=ip[i*2+1]==1?1:ip[i*2]==1?0:0; + end + for(Integer i=0;i<`INPUT/4;i=i+1) begin + pp2[i]=ip1[i*2+1]==1?1:ip1[i*2]==1?0:0; + end + for(Integer i=0;i<`INPUT/8;i=i+1) begin + pp3[i]=ip2[i*2+1]==1?1:ip2[i*2]==1?0:0; + end + for(Integer i=0;i<`INPUT/16;i=i+1) begin + pp4[i]=ip3[i*2+1]==1?1:ip3[i*2]==1?0:0; + end + for(Integer i=0;i<`INPUT/32;i=i+1) begin + pp5[i]=ip4[i*2+1]==1?1:ip4[i*2]==1?0:0; + end + for(Integer i=0;i<`INPUT/64;i=i+1) begin + pp6[i]=ip5[i*2+1]==1?1:ip5[i*2]==1?0:0; + end + for(Integer i=0;i<`INPUT/128;i=i+1) begin + pp7[i]=ip6[i*2+1]==1?1:ip6[i*2]==1?0:0; + end + for(Integer i=0;i<`INPUT/256;i=i+1) begin + pp8[i]=ip7[i*2+1]==1?1:ip7[i*2]==1?0:0; + end + for(Integer i=0;i<`INPUT/512;i=i+1) begin + pp9[i]=ip8[i*2+1]==1?1:ip8[i*2]==1?0:0; + end + + pp10=ip9[1]==1?1:ip9[0]==1?0:0; + ip10=ip9[1] | ip9[0]; + + result[0] = pp10; + let op9 = pp9[result[1:0]]; + result = {result[8:0],op9}; + let op8 = pp8[result[2:0]]; + result = {result[8:0],op8}; + let op7 = pp7[result[3:0]]; + result = {result[8:0],op7}; + let op6 = pp6[result[4:0]]; + result = {result[8:0],op6}; + let op5 = pp5[result[5:0]]; + result = {result[8:0],op5}; + let op4 = pp4[result[6:0]]; + result = {result[8:0],op4}; + let op3 = pp3[result[7:0]]; + result = {result[8:0],op3}; + let op2 = pp2[result[8:0]]; + result = {result[8:0],op2}; + let op1 = pp1[result[9:0]]; + result = {result[8:0],op1}; + return truncate(result); + endfunction + +method Bit#(irid) encode(Bit#(irpins) ip); + return fn_encoder(ip); +endmethod +endmodule + +(*synthesize*) +module mkSencoder(Ifc_encoder#(512)); + let ifc(); + mkencoder inst(ifc); + return ifc(); +endmodule + +endpackage diff --git a/src/peripherals/plic/plic.bsv b/src/peripherals/plic/plic.bsv index 0e94ee7..1f1661a 100644 --- a/src/peripherals/plic/plic.bsv +++ b/src/peripherals/plic/plic.bsv @@ -13,14 +13,17 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */ package plic; import Vector::*; - //import defined_parameters::*; import defined_types::*; import ConfigReg::*; import Semi_FIFOF::*; import AXI4_Lite_Types::*; import BUtils ::*; import ConcatReg ::*; + import encoder ::*; `include "instance_defines.bsv" + +`define INTERRUPT_LEVELS 8 + // import ConfigReg::*; /*Platform level interrupt controller: Refer to RISC-V privilege spec-v-1.10 chapter 7 @@ -51,7 +54,8 @@ package plic; */ -interface Ifc_PLIC#(numeric type addr_width,numeric type word_size,numeric type no_of_ir_pins); +interface Ifc_PLIC#(numeric type addr_width,numeric type word_size,numeric type no_of_ir_pins, + numeric type no_of_ir_levels); interface Vector#(no_of_ir_pins,Ifc_global_interrupt) ifc_external_irq; interface Ifc_program_registers#(addr_width,word_size) ifc_prog_reg; method ActionValue#(Tuple2#(Bool,Bool)) intrpt_note; @@ -59,95 +63,36 @@ interface Ifc_PLIC#(numeric type addr_width,numeric type word_size,numeric type endinterface //(*conflict_free = "rl_prioritise, prog_reg"*) -module mkplic(Ifc_PLIC#(addr_width,word_size,no_of_ir_pins)) +module mkplic(Ifc_PLIC#(addr_width,word_size,no_of_ir_pins,no_of_ir_levels)) provisos( - Log#(no_of_ir_pins, priority_bits), + Log#(no_of_ir_pins, ir_bits), + Log#(no_of_ir_levels, priority_bits), Mul#(8,word_size,data_width), - Add#(1,priority_bits,x_priority_bits), - Add#(msb_priority,1,priority_bits), - Add#(msb_priority_bits,1,no_of_ir_pins), - Add#(b__, no_of_ir_pins, data_width), - Add#(c__, priority_bits, data_width), - Add#(a__, 8, no_of_ir_pins), - Add#(e__, 32, data_width), - Add#(g__, 32, no_of_ir_pins), - Add#(f__, 3, priority_bits), - Add#(d__, 5, priority_bits) + //Mul#(3,no_iterations,ir_bits), + Add#(1,ir_bits,x_ir_bits), + Add#(msb_ir_bits,1,ir_bits), + Add#(msb_ir_pins,1,no_of_ir_pins), + Add#(msb_priority_levels,1,no_of_ir_levels), + Add#(msb_priority_bits,1,priority_bits), + Add#(a__, no_of_ir_levels, data_width), + Add#(b__, ir_bits, data_width), + Add#(c__, no_of_ir_pins, 1024), + Add#(d__, ir_bits, 10), + Add#(f__, no_of_ir_levels, 1024), + Add#(g__, priority_bits, 10), + Add#(h__, no_of_ir_levels, 32), + Add#(e__, 32, data_width) + //Mul#(no_iterations, 3, ir_bits), ); let v_no_of_ir_pins = valueOf(no_of_ir_pins); - let v_priority_bits = valueOf(priority_bits); - let v_msb_priority_bits = valueOf(msb_priority_bits); - let v_msb_priority = valueOf(msb_priority); + let v_ir_bits = valueOf(ir_bits); + let v_msb_ir_bits = valueOf(msb_ir_bits); + let v_msb_ir_pins = valueOf(msb_ir_pins); + let v_msb_priority = valueOf(msb_priority_levels); let v_data_width = valueOf(data_width); //(* noinline *) - /* This function defines the working of priority encoder with 4 bit inputs */ - function Bit#(8) priority_encoder(Bit#(8) inp, Bool alu_free); - Bit#(8) outp = 0; - if(alu_free) begin - if(inp[0]==1) - outp[0] = 1'b1; - else if(inp[1]==1) - outp[1] = 1'b1; - else if(inp[2]==1) - outp[2] = 1'b1; - else if(inp[3]==1) - outp[3] = 1'b1; - else if(inp[4]==1) - outp[4] = 1'b1; - else if(inp[5]==1) - outp[5] = 1'b1; - else if(inp[6]==1) - outp[6] = 1'b1; - else if(inp[7]==1) - outp[7] = 1'b1; - end - - return outp; - endfunction - - function bit any_req(Bit#(8) inp); - return inp[0] | inp[1] | inp[2] | inp[3] | inp[4] | inp[5] | inp[6] | inp[7]; - endfunction - - /* Encodes the grant vector */ - function Bit#(x_priority_bits) encoder(Bit#(no_of_ir_pins) inp); - Bit#(priority_bits) outp = 0; - bit outp_valid = 1'b1; - for(Integer i = 0; i < v_no_of_ir_pins; i = i+1) begin - if(inp[i]==1) - outp = fromInteger(i); - end - return {outp_valid,outp}; - endfunction - - function Reg#(t) readOnlyReg(t r); - return (interface Reg; - method t _read = r; - method Action _write(t x) = noAction; - endinterface); - endfunction - - /* Request vectors are passed down the tree and the grants are given back */ - function Bit#(no_of_ir_pins) encoder_tree(Bit#(no_of_ir_pins) inp); - Bit#(no_of_ir_pins) outp = 0; - //request to root - Bit#(8) root_reqs; - - //grant from root - Bit#(8) root_grants; - - for(Integer i=0;i<8;i=i+1) - root_reqs[i] = any_req(inp[8*fromInteger(i)+7:8*fromInteger(i)]); - - root_grants = priority_encoder(root_reqs, True); - - //grants are passed back to leaves - for(Integer i=0;i<8;i=i+1) - outp[8*fromInteger(i)+7:8*fromInteger(i)] = priority_encoder(inp[8*fromInteger(i)+7:8*fromInteger(i)], unpack(root_grants[i])); - return outp; - endfunction Vector#(no_of_ir_pins,Array#(Reg#(Bool))) rg_ip <- replicateM(mkCReg(2,False)); Reg#(Bool) rg_ie[v_no_of_ir_pins]; @@ -156,57 +101,117 @@ module mkplic(Ifc_PLIC#(addr_width,word_size,no_of_ir_pins)) rg_ie[i] = readOnlyReg(True); else rg_ie[i] <- mkReg(False); - Reg#(Bit#(32)) rg_priority_low[v_no_of_ir_pins]; + Reg#(Bit#(no_of_ir_levels)) rg_priority_low[v_no_of_ir_pins]; for(Integer i =0; i < v_no_of_ir_pins; i=i+1) if(i==28 || i == 29) - rg_priority_low[i] = readOnlyReg(32'h00000001); + rg_priority_low[i] = readOnlyReg(1); else rg_priority_low[i] <- mkConfigReg(0); - Reg#(Bit#(no_of_ir_pins)) rg_priority[v_no_of_ir_pins]; + Reg#(Bit#(32)) rg_priority[v_no_of_ir_pins]; for(Integer i=0;i < v_no_of_ir_pins;i=i+1) rg_priority[i] = concatReg2(readOnlyReg(0), rg_priority_low[i]); - Reg#(Bit#(5)) rg_priority_threshold_low <- mkReg(0); - Reg#(Bit#(priority_bits)) rg_priority_threshold = concatReg2(readOnlyReg(0),rg_priority_threshold_low); - Reg#(Bit#(priority_bits)) rg_interrupt_id <- mkConfigReg(0); + Reg#(Bit#(no_of_ir_levels)) rg_priority_threshold <- mkReg(0); + Reg#(Bit#(ir_bits)) rg_interrupt_id <- mkConfigReg(0); Reg#(Bool) rg_interrupt_valid <- mkConfigReg(False); - Reg#(Maybe#(Bit#(priority_bits))) rg_completion_id <- mkReg(tagged Invalid); + Reg#(Maybe#(Bit#(ir_bits))) rg_completion_id <- mkReg(tagged Invalid); + Reg#(Bit#(no_of_ir_pins)) rg_total_priority <- mkReg(0); + Reg#(Bit#(1)) rg_plic_state <- mkReg(0); //TODO put an enum later + Reg#(Bit#(no_of_ir_levels)) rg_winner_priority <- mkReg(0); + Ifc_encoder#(no_of_ir_levels) ir_priority_encoder <- mkencoder(); + Ifc_encoder#(no_of_ir_pins) irencoder <- mkencoder(); - rule rl_prioritise; + rule rl_prioritise(rg_plic_state==0); Bit#(priority_bits) winner_priority = 0; - Bit#(priority_bits) winner_interrupts = 0; - Bit#(x_priority_bits) ir_id_valid = 0; - Bit#(no_of_ir_pins) lv_priority = 0; + Bit#(ir_bits) winner_interrupts = 0; + Bit#(x_ir_bits) ir_id_valid = 0; + Bit#(no_of_ir_levels) lv_priority = 0; Bit#(no_of_ir_pins) lv_total_priority = 0; for(Integer i = 0; i < v_no_of_ir_pins; i = i + 1) begin if(rg_ip[i][1] && rg_ie[i]) begin - lv_priority = lv_priority | rg_priority[i]; - winner_interrupts = fromInteger(i); + lv_priority = lv_priority | truncate(rg_priority[i]); `ifdef verbose $display($time,"\tInterrupt id %d and priority is %d", i, lv_priority);`endif end end - winner_priority = encoder(encoder_tree(lv_priority))[v_msb_priority:0]; + winner_priority = ir_priority_encoder.encode(lv_priority); `ifdef verbose $display($time,"\t winner priority is %d", winner_priority);`endif for(Integer i = 0; i < v_no_of_ir_pins; i = i + 1) begin if(rg_priority[i][winner_priority] == 1 && rg_ip[i][1] && rg_ie[i]) lv_total_priority[i] = 1; end - if(lv_total_priority!=0) - winner_interrupts = encoder(encoder_tree(lv_total_priority))[v_msb_priority:0]; - if(winner_interrupts!=0) begin - ir_id_valid = encoder(rg_priority[winner_interrupts]); - if(winner_priority <= rg_priority_threshold) - begin - - `ifdef verbose $display("Interrupt valid");`endif - rg_interrupt_id <= winner_interrupts; - rg_interrupt_valid <= True; - $display($time,"\t The highest priority interrupt is %d and the priority is ", winner_interrupts, winner_priority); - end + if(lv_total_priority!=0) begin + rg_total_priority <= lv_total_priority; + rg_plic_state <= 1; + Bit#(no_of_ir_levels) lv_winner_priority = 0; + lv_winner_priority[winner_priority] = 1; + rg_winner_priority <= lv_winner_priority; end endrule + rule rl_encoder(rg_plic_state==1); + Bit#(ir_bits) interrupt_id = irencoder.encode(rg_total_priority); + if(interrupt_id!=0 && rg_priority_threshold >= rg_winner_priority) begin + `ifdef verbose $display("Interrupt valid");`endif + rg_interrupt_id <= interrupt_id; + rg_interrupt_valid <= True; + $display($time,"\t The highest priority interrupt is %d and the priority is ", interrupt_id, rg_winner_priority); + end + rg_plic_state <= 0; + + + //if(lv_total_priority!=0) + //winner_interrupts = encoder(encoder_tree(lv_total_priority))[v_msb_priority:0]; + //if(winner_interrupts!=0) begin + // if(winner_priority <= rg_priority_threshold) + // begin + // + // `ifdef verbose $display("Interrupt valid");`endif + // rg_interrupt_id <= winner_interrupts; + // rg_interrupt_valid <= True; + // $display($time,"\t The highest priority interrupt is %d and the priority is ", winner_interrupts, winner_priority); + // end + //end + endrule + + + //for(Integer i = 0; i> 2; if(mem_req.ld_st == Load) begin - source_id = address[v_msb_priority:0]; + source_id = address[v_msb_ir_bits:0]; `ifdef verbose $display($time,"\tPLIC : source %d Priority set to %h", source_id, mem_req.write_data);`endif data_return = zeroExtend(rg_priority[source_id]); end else if(mem_req.ld_st == Store) begin - Bit#(no_of_ir_pins) store_data; + Bit#(data_width) store_data; if(mem_req.byte_offset==0) - store_data=mem_req.write_data[v_msb_priority_bits:0]; + store_data=mem_req.write_data[v_msb_ir_pins:0]; else store_data=mem_req.write_data[v_data_width-1:v_data_width-v_no_of_ir_pins]; mem_req.byte_offset = mem_req.byte_offset >> 2; - source_id = address[v_msb_priority:0] | zeroExtend(mem_req.byte_offset); + source_id = address[v_msb_ir_bits:0]; $display($time,"\tPLIC : source %d Priority set to %h", source_id, store_data); - rg_priority[source_id] <= store_data; + rg_priority[source_id] <= truncate(store_data); end end - //else if(address < 'h0C002000) begin - else if(address<`PLICBase+'h2000)begin + else if(address < 'h0C002000) begin if(mem_req.ld_st == Load) begin - source_id = address[v_msb_priority:0]; + source_id = address[v_msb_ir_bits:0]; source_id = source_id << 3; for(Integer i = 0; i < 8; i = i+1) data_return[i] = pack(rg_ip[source_id + fromInteger(i)][1]); end else if(mem_req.ld_st == Store) begin - source_id = zeroExtend(mem_req.byte_offset); + source_id = address[v_msb_ir_bits:0]; source_id = source_id << 3; for(Integer i = 0; i < 8; i = i+1) begin `ifdef verbose $display($time,"\tPLIC : pending interrupt %b id %d", mem_req.write_data[i], source_id);`endif @@ -268,17 +271,16 @@ interface ifc_prog_reg = interface Ifc_program_registers; end end end - //else if(address < 'h0C020000) begin - else if(address < `PLICBase+'h20000)begin + else if(address < 'h0C020000) begin if(mem_req.ld_st == Load) begin - source_id = address[v_msb_priority:0]; + source_id = address[v_msb_ir_bits:0]; source_id = source_id << 3; for(Integer i = 0; i < 8; i = i+1) data_return[i] = pack(rg_ie[source_id + fromInteger(i)]); `ifdef verbose $display($time,"PLIC: Printing Source Enable Interrupt: %h data_return: %h",source_id,data_return); `endif end else if(mem_req.ld_st == Store) begin - source_id = zeroExtend(mem_req.byte_offset); + source_id = address[v_msb_ir_bits:0]; source_id = source_id << 3; for(Integer i = 0; i < 8; i = i+1) begin `ifdef verbose $display($time,"\tPLIC : enabled interrupt %b id %d", mem_req.write_data[i], source_id);`endif @@ -286,23 +288,21 @@ interface ifc_prog_reg = interface Ifc_program_registers; end end end - // else if(address == 'hC200000) begin - else if(address ==`PLICBase+'h200000)begin + else if(address == 'hC200000) begin if(mem_req.ld_st == Load) begin data_return = zeroExtend(rg_priority_threshold); end else if(mem_req.ld_st == Store) rg_priority_threshold <= mem_req.write_data[v_msb_priority:0]; end - // else if(address == 'hC200004) begin - else if(address == `PLICBase+'h200004)begin + else if(address == 'hC200004) begin if(mem_req.ld_st == Load) begin data_return = zeroExtend(rg_interrupt_id); rg_ip[rg_interrupt_id][1] <= False; `ifdef verbose $display($time,"rg_ip is made false here"); `endif end else if(mem_req.ld_st == Store) begin - source_id = mem_req.write_data[v_msb_priority:0]; + source_id = mem_req.write_data[v_msb_ir_bits:0]; rg_completion_id <= tagged Valid source_id; `ifdef verbose $display("rg_completion_id is made tagged valid and completion is signaled-- source_id: %d",source_id); `endif end @@ -339,7 +339,7 @@ endinterface module mkplicperipheral(Ifc_PLIC_AXI); AXI4_Lite_Slave_Xactor_IFC #(`PADDR, `Reg_width, `USERSPACE) s_xactor_plic <- mkAXI4_Lite_Slave_Xactor; -Ifc_PLIC#(`PADDR, `DCACHE_WORD_SIZE, `INTERRUPT_PINS) plic <- mkplic(); +Ifc_PLIC#(`PADDR, `DCACHE_WORD_SIZE, `INTERRUPT_PINS, `INTERRUPT_LEVELS) plic <- mkplic(); (*preempts="rl_config_plic_reg_read, rl_config_plic_reg_write"*) rule rl_config_plic_reg_write; @@ -362,11 +362,12 @@ Ifc_PLIC#(`PADDR, `DCACHE_WORD_SIZE, `INTERRUPT_PINS) plic <- mkplic(); let ar <- pop_o(s_xactor_plic.o_rd_addr); let x <- plic.ifc_prog_reg.prog_reg(UncachedMemReq{address : ar.araddr, transfer_size : 'd3, u_signed : 0, byte_offset : 0, ld_st : Load}); -// if(ar.arsize==3'd0) -// x = duplicate(x[7:0]); -// else if(ar.arsize==3'd1) -// x = duplicate(x[15:0]); -// else if(ar.arsize==3'd2) + if(ar.arsize==3'd0) + x = duplicate(x[7:0]); + else if(ar.arsize==3'd1) + x = duplicate(x[15:0]); + else if(ar.arsize==3'd2) + x = duplicate(x[7:0]); let r = AXI4_Lite_Rd_Data {rresp: AXI4_LITE_OKAY, rdata: duplicate(x), ruser: 0}; s_xactor_plic.i_rd_data.enq(r);