diff --git a/rocket/src/main/scala/cpu.scala b/rocket/src/main/scala/cpu.scala index e543d0e0..8cde5d50 100644 --- a/rocket/src/main/scala/cpu.scala +++ b/rocket/src/main/scala/cpu.scala @@ -53,12 +53,11 @@ class rocketProc extends Component dpath.io.host ^^ io.host; ctrl.io.host.start := io.host.start; dpath.io.debug ^^ io.debug; -// dpath.io.imem.resp_data ^^ io.imem.resp_data; - - // FIXME: make this less verbose + // FIXME: try to make this more compact + // connect ITLB to I$, ctrl, dpath - itlb.io.cpu.invalidate := dpath.io.ptbr_wen || ctrl.io.flush_inst; + itlb.io.cpu.invalidate := dpath.io.ptbr_wen; itlb.io.cpu.status := dpath.io.ctrl.status; itlb.io.cpu.req_val := ctrl.io.imem.req_val; itlb.io.cpu.req_asid := Bits(0,ASID_BITS); // FIXME: connect to PCR @@ -76,7 +75,6 @@ class rocketProc extends Component // connect DTLB to D$ arbiter, ctrl+dpath -// dtlb.io.cpu.invalidate := Bool(false); // FIXME dtlb.io.cpu.invalidate := dpath.io.ptbr_wen; dtlb.io.cpu.status := dpath.io.ctrl.status; dtlb.io.cpu.req_val := ctrl.io.dmem.req_val; @@ -99,14 +97,10 @@ class rocketProc extends Component arb.io.mem ^^ io.dmem // connect arbiter to ctrl+dpath+DTLB -// arb.io.cpu.req_val := dtlb.io.cpu.resp_val; arb.io.cpu.req_val := ctrl.io.dmem.req_val; arb.io.cpu.req_cmd := ctrl.io.dmem.req_cmd; arb.io.cpu.req_type := ctrl.io.dmem.req_type; -// arb.io.cpu.dtlb_busy := dtlb.io.cpu.resp_busy; arb.io.cpu.dtlb_miss := dtlb.io.cpu.resp_miss; - -// arb.io.cpu.req_addr := dtlb.io.cpu.resp_addr; arb.io.cpu.req_idx := dpath.io.dmem.req_addr(PGIDX_BITS-1,0); arb.io.cpu.req_ppn := dtlb.io.cpu.resp_ppn; arb.io.cpu.req_data := dpath.io.dmem.req_data; diff --git a/rocket/src/main/scala/dcache.scala b/rocket/src/main/scala/dcache.scala index d71b2155..e7ac5744 100644 --- a/rocket/src/main/scala/dcache.scala +++ b/rocket/src/main/scala/dcache.scala @@ -48,7 +48,7 @@ class rocketDCacheStoreGen extends Component { val req_type = Bits(3, 'input); val req_addr_lsb = Bits(3, 'input); val req_data = Bits(64, 'input); - val store_wmask = Bits(64, 'output); + val store_wmask = Bits(8, 'output); val store_data = Bits(64, 'output); } @@ -86,16 +86,8 @@ class rocketDCacheStoreGen extends Component { Mux(io.req_type === MT_D, wmask_d, UFix(0, 8))))); - io.store_wmask := - Cat(Fill(8, store_wmask_byte(7)), - Fill(8, store_wmask_byte(6)), - Fill(8, store_wmask_byte(5)), - Fill(8, store_wmask_byte(4)), - Fill(8, store_wmask_byte(3)), - Fill(8, store_wmask_byte(2)), - Fill(8, store_wmask_byte(1)), - Fill(8, store_wmask_byte(0))); - + io.store_wmask := store_wmask_byte; + io.store_data := Mux(io.req_type === MT_B, Fill(8, io.req_data( 7,0)), Mux(io.req_type === MT_H, Fill(4, io.req_data(15,0)), @@ -183,7 +175,7 @@ class rocketDCacheDM(lines: Int) extends Component { val offsetmsb = indexlsb-1; val offsetlsb = 3; - val s_reset :: s_ready :: s_replay_load :: s_start_writeback :: s_writeback :: s_req_refill :: s_refill :: s_resolve_miss :: Nil = Enum(8) { UFix() }; + val s_reset :: s_ready :: s_replay_load :: s_write_amo :: s_start_writeback :: s_writeback :: s_req_refill :: s_refill :: s_resolve_miss :: Nil = Enum(9) { UFix() }; val state = Reg(resetVal = s_reset); // idx arrives one clock cycle prior to ppn b/c of DTLB @@ -194,6 +186,7 @@ class rocketDCacheDM(lines: Int) extends Component { val r_cpu_req_type = Reg(resetVal = Bits(0,3)); val r_cpu_req_tag = Reg(resetVal = Bits(0,5)); val r_cpu_resp_val = Reg(resetVal = Bool(false)); + val r_amo_data = Reg(resetVal = Bits(0,64)); val p_store_data = Reg(resetVal = Bits(0,64)); val p_store_idx = Reg(resetVal = Bits(0,PGIDX_BITS)); @@ -203,11 +196,13 @@ class rocketDCacheDM(lines: Int) extends Component { val req_store = (io.cpu.req_cmd === M_XWR); val req_load = (io.cpu.req_cmd === M_XRD) || (io.cpu.req_cmd === M_PRD); val req_flush = (io.cpu.req_cmd === M_FLA); + val req_amo = io.cpu.req_cmd(3).toBool; val r_req_load = (r_cpu_req_cmd === M_XRD) || (r_cpu_req_cmd === M_PRD); val r_req_store = (r_cpu_req_cmd === M_XWR); val r_req_flush = (r_cpu_req_cmd === M_FLA); val r_req_ptw_load = (r_cpu_req_cmd === M_PRD); - + val r_req_amo = r_cpu_req_cmd(3).toBool; + when (io.cpu.req_val && io.cpu.req_rdy) { r_cpu_req_idx <== io.cpu.req_idx; r_cpu_req_cmd <== io.cpu.req_cmd; @@ -273,7 +268,7 @@ class rocketDCacheDM(lines: Int) extends Component { // load/store addresses conflict if they are to any part of the same 64 bit word val addr_match = (r_cpu_req_idx(PGIDX_BITS-1,offsetlsb) === p_store_idx(PGIDX_BITS-1,offsetlsb)); - val ldst_conflict = tag_valid && tag_match && r_req_load && p_store_valid && addr_match; + val ldst_conflict = tag_valid && tag_match && (r_req_load || r_req_amo) && p_store_valid && addr_match; val store_hit = r_cpu_req_val && !io.cpu.dtlb_miss && tag_hit && r_req_store ; // write the pending store data when the cache is idle, when the next command isn't a load @@ -297,6 +292,10 @@ class rocketDCacheDM(lines: Int) extends Component { p_store_type <== io.cpu.req_type; } + when (io.cpu.req_val && io.cpu.req_rdy && req_amo) { + r_amo_data <== io.cpu.req_data; + } + when (store_hit && !drain_store) { p_store_valid <== Bool(true); } @@ -304,52 +303,85 @@ class rocketDCacheDM(lines: Int) extends Component { p_store_valid <== Bool(false); db_array <== db_array.bitSet(p_store_idx(PGIDX_BITS-1,offsetbits).toUFix, UFix(1,1)); } - when (resolve_store) { + when (resolve_store || (state === s_write_amo)) { db_array <== db_array.bitSet(p_store_idx(PGIDX_BITS-1,offsetbits).toUFix, UFix(1,1)); } when (tag_we) { db_array <== db_array.bitSet(r_cpu_req_idx(PGIDX_BITS-1,offsetbits).toUFix, UFix(0,1)); } - // generate write mask and data signals for stores + // generate write mask and data signals for stores and amos val storegen = new rocketDCacheStoreGen(); storegen.io.req_addr_lsb := p_store_idx(2,0); storegen.io.req_data := p_store_data; - storegen.io.req_type := p_store_type + storegen.io.req_type := p_store_type; val store_data = Fill(2, storegen.io.store_data); - val store_wmask_d = storegen.io.store_wmask; + val store_wmask_b = storegen.io.store_wmask; + val store_wmask_d = Cat(Fill(8, store_wmask_b(7)), + Fill(8, store_wmask_b(6)), + Fill(8, store_wmask_b(5)), + Fill(8, store_wmask_b(4)), + Fill(8, store_wmask_b(3)), + Fill(8, store_wmask_b(2)), + Fill(8, store_wmask_b(1)), + Fill(8, store_wmask_b(0))); val store_idx_sel = p_store_idx(offsetlsb).toBool; val store_wmask = Mux(store_idx_sel, Cat(store_wmask_d, Bits(0,64)), Cat(Bits(0,64), store_wmask_d)); // data array val data_array = new rocketSRAMsp(lines*4, 128); + val data_array_rdata = data_array.io.q; + val resp_data = Mux(r_cpu_req_idx(offsetlsb).toBool, data_array_rdata(127, 64), data_array_rdata(63,0)); + val r_resp_data = Reg(resp_data); + + // ALU for AMOs + val amo_wmask = + Mux(r_cpu_req_type === MT_D, ~Bits(0,8), + Mux(r_cpu_req_idx(2).toBool, Cat(~Bits(0,4), Bits(0,4)), + Cat(Bits(0,4), ~Bits(0,4)))); + + val amo_alu = new rocketDCacheAmoALU(); + amo_alu.io.cmd := r_cpu_req_cmd; + amo_alu.io.wmask := amo_wmask; + amo_alu.io.lhs := r_resp_data.toUFix; + amo_alu.io.rhs := r_amo_data.toUFix; + val amo_alu_out = amo_alu.io.result; + data_array.io.a := Mux(drain_store || resolve_store, p_store_idx(PGIDX_BITS-1, offsetmsb-1), Mux((state === s_writeback) && io.mem.req_rdy, Cat(r_cpu_req_idx(PGIDX_BITS-1, offsetbits), rr_count_next), Mux((state === s_start_writeback) || (state === s_writeback) || (state === s_refill), Cat(r_cpu_req_idx(PGIDX_BITS-1, offsetbits), rr_count), - Mux((state === s_resolve_miss) || (state === s_replay_load), r_cpu_req_idx(PGIDX_BITS-1, offsetmsb-1), + Mux((state === s_resolve_miss) || (state === s_replay_load) || (state === s_write_amo), r_cpu_req_idx(PGIDX_BITS-1, offsetmsb-1), io.cpu.req_idx(PGIDX_BITS-1, offsetmsb-1))))).toUFix; - data_array.io.d := Mux((state === s_refill), io.mem.resp_data, store_data); - data_array.io.we := ((state === s_refill) && io.mem.resp_val) || drain_store || resolve_store; + data_array.io.d := + Mux((state === s_refill), io.mem.resp_data, + Mux((state === s_write_amo), amo_alu_out, + store_data)); + data_array.io.we := + ((state === s_refill) && io.mem.resp_val) || + (state === s_write_amo) || + drain_store || resolve_store; + data_array.io.bweb := Mux((state === s_refill), ~Bits(0,128), store_wmask); data_array.io.ce := - (io.cpu.req_val && io.cpu.req_rdy && req_load) || + (io.cpu.req_val && io.cpu.req_rdy && (req_load || req_amo)) || (state === s_start_writeback) || (state === s_writeback) || - ((state === s_resolve_miss) && r_req_load) || + ((state === s_resolve_miss) && (r_req_load || r_req_amo)) || (state === s_replay_load); - - val data_array_rdata = data_array.io.q; // signal a load miss when the data isn't present in the cache and when it's in the pending store data register - // (causes the cache to block for 2 cycles and the load instruction is replayed) - val load_miss = !io.cpu.dtlb_miss && (state === s_ready) && r_cpu_req_val && r_req_load && (!tag_hit || (p_store_valid && addr_match)); + // (causes the cache to block for 2 cycles and the load or amo instruction is replayed) + val load_miss = + !io.cpu.dtlb_miss && + (state === s_ready) && r_cpu_req_val && (r_req_load || r_req_amo) && (!tag_hit || (p_store_valid && addr_match)); // output signals // busy when there's a load to the same address as a pending store, or on a cache miss, or when executing a flush - io.cpu.req_rdy := (state === s_ready) && !io.cpu.dtlb_miss && !ldst_conflict && (!r_cpu_req_val || (tag_hit && !r_req_flush)); - io.cpu.resp_val := !io.cpu.dtlb_miss && ((state === s_ready) && tag_hit && r_req_load && !(p_store_valid && addr_match)) || + io.cpu.req_rdy := (state === s_ready) && !io.cpu.dtlb_miss && !ldst_conflict && (!r_cpu_req_val || (tag_hit && !(r_req_flush || r_req_amo))); + io.cpu.resp_val := !io.cpu.dtlb_miss && + ((state === s_ready) && tag_hit && (r_req_load || r_req_amo) && !(p_store_valid && addr_match)) || ((state === s_resolve_miss) && r_req_flush) || r_cpu_resp_val; @@ -358,15 +390,13 @@ class rocketDCacheDM(lines: Int) extends Component { (((r_cpu_req_type === MT_W) || (r_cpu_req_type === MT_WU)) && (r_cpu_req_idx(1,0) != Bits(0,2))) || ((r_cpu_req_type === MT_D) && (r_cpu_req_idx(2,0) != Bits(0,3))); - io.cpu.xcpt_ma_ld := r_cpu_req_val && r_req_load && misaligned; - io.cpu.xcpt_ma_st := r_cpu_req_val && r_req_store && misaligned; + io.cpu.xcpt_ma_ld := r_cpu_req_val && (r_req_load || r_req_amo) && misaligned; + io.cpu.xcpt_ma_st := r_cpu_req_val && (r_req_store || r_req_amo) && misaligned; io.cpu.resp_miss := load_miss; // tag MSB distinguishes between loads destined for the PTW and CPU io.cpu.resp_tag := Cat(r_req_ptw_load, r_cpu_req_type, r_cpu_req_idx(2,0), r_cpu_req_tag); - io.cpu.resp_data := - Mux(r_cpu_req_idx(offsetlsb).toBool, data_array_rdata(127, 64), - data_array_rdata(63,0)); + io.cpu.resp_data := resp_data; io.mem.req_val := (state === s_req_refill) || (state === s_writeback); io.mem.req_rw := (state === s_writeback); @@ -388,9 +418,12 @@ class rocketDCacheDM(lines: Int) extends Component { when (ldst_conflict) { state <== s_replay_load; } - when (!r_cpu_req_val || (tag_hit && !r_req_flush)) { + when (!r_cpu_req_val || (tag_hit && !(r_req_flush || r_req_amo))) { state <== s_ready; } + when (tag_hit && r_req_amo) { + state <== s_write_amo; + } when (tag_valid & tag_dirty) { state <== s_start_writeback; } @@ -404,6 +437,9 @@ class rocketDCacheDM(lines: Int) extends Component { is (s_replay_load) { state <== s_ready; } + is (s_write_amo) { + state <== s_ready; + } is (s_start_writeback) { state <== s_writeback; } @@ -425,9 +461,42 @@ class rocketDCacheDM(lines: Int) extends Component { when (io.mem.resp_val && (rr_count === UFix(3,2))) { state <== s_resolve_miss; } } is (s_resolve_miss) { + when (r_req_amo) { + state <== s_write_amo; + } state <== s_ready; } } } +class rocketDCacheAmoALU extends Component { + val io = new Bundle { + val cmd = Bits(4, 'input); + val wmask = Bits(8, 'input); + val lhs = UFix(64, 'input); + val rhs = UFix(64, 'input); + val result = UFix(64, 'output); + } + +// val signed_cmp = (op === M_XA_MIN) || (op === M_XA_MAX); +// val sub = (op === M_XA_MIN) || (op === M_XA_MINU) || +// (op === M_XA_MAX) || (op === M_XA_MAXU); + + val adder_lhs = Cat(io.lhs(63,32),io.wmask(3) & io.lhs(31), io.lhs(30,0)).toUFix; + val adder_rhs = Cat(io.rhs(63,32),io.wmask(3) & io.rhs(31), io.rhs(30,0)).toUFix; +// val adder_rhs = Cat(Mux(sub, ~io.rhs, io.rhs), sub).toUFix; +// val sum = adder_lhs + adder_rhs; +// val adder_out = sum(64,1); + val adder_out = adder_lhs + adder_rhs; + val alu_out = Wire() { UFix() }; + switch (io.cmd) { +// is (M_XA_ADD) { alu_out <== adder_out; } + is (M_XA_SWAP) { alu_out <== io.rhs; } + is (M_XA_AND) { alu_out <== io.lhs & io.rhs; } + is (M_XA_OR) { alu_out <== io.lhs | io.rhs; } + } + alu_out <== adder_out; + io.result := alu_out; } + +} \ No newline at end of file diff --git a/rocket/src/main/scala/dpath.scala b/rocket/src/main/scala/dpath.scala index d2340ccb..7129fc4e 100644 --- a/rocket/src/main/scala/dpath.scala +++ b/rocket/src/main/scala/dpath.scala @@ -45,7 +45,7 @@ class rocketDpath extends Component val alu = new rocketDpathALU(); val ex_alu_out = alu.io.out; - val ex_jr_target = ex_alu_out(31,0); + val ex_jr_target = ex_alu_out(VADDR_BITS,0); val div = new rocketDivider(64); val div_result = div.io.div_result_bits; @@ -342,7 +342,7 @@ class rocketDpath extends Component // D$ request interface (registered inside D$ module) // other signals (req_val, req_rdy) connect to control module - io.dmem.req_addr := ex_alu_out(PADDR_BITS-1,0); + io.dmem.req_addr := ex_alu_out(VADDR_BITS-1,0); io.dmem.req_data := ex_reg_rs2; io.dmem.req_tag := ex_reg_waddr;