public virtual void PerformOperation(InternalRequest internalReq) { FlashChipDie targetDie = this.Dies[internalReq.TargetPageAddress.DieID]; if (targetDie.Status != DieStatus.Idle && (internalReq.ExecutionType != InternalRequestExecutionType.Multiplane) && (internalReq.ExecutionType != InternalRequestExecutionType.InterleavedMultiplane)) { throw new Exception("Executing operation on a busy die"); } if (targetDie.Planes[internalReq.TargetPageAddress.PlaneID].Status == PlaneStatus.Busy) { throw new Exception("Executing operation on a busy plane"); } targetDie.CurrentExecutingOperationCount++; targetDie.Status = DieStatus.Busy; targetDie.Planes[internalReq.TargetPageAddress.PlaneID].Status = PlaneStatus.Busy; targetDie.Planes[internalReq.TargetPageAddress.PlaneID].CurrentExecutingRequest = internalReq; ulong executionTime = 0; switch (internalReq.Type) { case InternalRequestType.Read: this.Status = FlashChipStatus.Reading; /* tR + tRR * According to micron's manual, after read operation accomplishment, we have to wait for ready signals to be driven*/ executionTime = readLatency + readDataOutputReadyTime; break; case InternalRequestType.Write: this.Status = FlashChipStatus.Writing; executionTime = programLatency; break; case InternalRequestType.Clean: this.Status = FlashChipStatus.Erasing; executionTime = eraseLatency; //This is a normal erase requeset break; default: throw new Exception("Unhandled operation type"); } internalReq.ExpectedFinishTime = XEngineFactory.XEngine.Time + executionTime; internalReq.FlashChipExecutionEvent = new XEvent(internalReq.ExpectedFinishTime, this, internalReq, 0); XEngineFactory.XEngine.EventList.InsertXEvent(internalReq.FlashChipExecutionEvent); CurrentExecutingOperationCount++; if (CurrentExecutingOperationCount == 1) { ThisRoundExecutionStart = XEngineFactory.XEngine.Time; ThisRoundExecutionFinish = ulong.MaxValue; ExpectedFinishTime = internalReq.ExpectedFinishTime; IssueTimeOfExecutingRequest = internalReq.IssueTime; } }
public FlashChip( string id, uint channelID, uint localChipID, uint overallChipID, uint dieNo, uint PlaneNoPerDie, uint BlockNoPerPlane, uint PageNoPerBlock, uint BlockEraseLimit, ulong readLatency, ulong programLatency, ulong eraseLatency, ulong readDataOutputReadyTime ) : base(id) { this.ChannelID = channelID; this.LocalChipID = localChipID; this.OverallChipID = overallChipID; this.CurrentActiveDieID = 0; this.PlaneNoPerDie = PlaneNoPerDie; this.BlockNoPerPlane = BlockNoPerPlane; this.PageNoPerBlock = PageNoPerBlock; this.BlockEraseLimit = BlockEraseLimit; this.Dies = new FlashChipDie[dieNo]; for (uint dieID = 0; dieID < dieNo; dieID++) { Dies[dieID] = new FlashChipDie(channelID, overallChipID, localChipID, dieID, PlaneNoPerDie, BlockNoPerPlane, PageNoPerBlock); } this.ReadCount = 0; this.ProgamCount = 0; this.EraseCount = 0; this.readLatency = readLatency; this.programLatency = programLatency; this.eraseLatency = eraseLatency; this.readDataOutputReadyTime = readDataOutputReadyTime; this.Status = FlashChipStatus.Idle; }
public override void ProcessXEvent(XEvent e) { if (e.Removed) { return; } //Just only one xevent: OperationFinished InternalRequest targetRequest = e.Parameters as InternalRequest; FlashChipDie targetDie = this.Dies[targetRequest.TargetPageAddress.DieID]; targetDie.CurrentExecutingOperationCount--; if (targetDie.CurrentExecutingOperationCount == 0) { targetDie.Status = DieStatus.Idle; } targetDie.Planes[targetRequest.TargetPageAddress.PlaneID].Status = PlaneStatus.Idle; targetDie.Planes[targetRequest.TargetPageAddress.PlaneID].CurrentExecutingRequest = null; CurrentExecutingOperationCount--; if (CurrentExecutingOperationCount == 0) { Status = FlashChipStatus.Idle; totalCommandExecutionPeriod += XEngineFactory.XEngine.Time - ThisRoundExecutionStart; ThisRoundExecutionFinish = XEngineFactory.XEngine.Time; } switch (targetRequest.Type) { case InternalRequestType.Read: this.ReadCount++; targetDie.Planes[targetRequest.TargetPageAddress.PlaneID].ReadCount++; targetRequest.ExecutionTime += this.readLatency; this.Status = FlashChipStatus.Waiting; //Either a normal read (waiting for read data transfer) or a copyback read (waiting for write execution) this.CurrentWaitingTransfers++; if (targetDie.Status == DieStatus.Idle) { targetDie.TotalReadExecutionPeriod += readLatency; } break; case InternalRequestType.Write: this.ProgamCount++; targetDie.Planes[targetRequest.TargetPageAddress.PlaneID].ProgamCount++; targetRequest.ExecutionTime += this.programLatency; if (targetDie.Status == DieStatus.Idle) { targetDie.TotalProgramExecutionPeriod += programLatency; } break; case InternalRequestType.Clean: this.EraseCount++; targetDie.Planes[targetRequest.TargetPageAddress.PlaneID].EraseCount++; targetRequest.ExecutionTime += this.eraseLatency; FlashChipBlock targetBlock = this.Dies[targetRequest.TargetPageAddress.DieID].Planes[targetRequest.TargetPageAddress.PlaneID].Blocks[targetRequest.TargetPageAddress.BlockID]; targetDie.Planes[targetRequest.TargetPageAddress.PlaneID].FreePagesNo += (PageNoPerBlock - targetBlock.FreePageNo); targetBlock.FreePageNo = PageNoPerBlock; targetBlock.InvalidPageNo = 0; targetBlock.LastWrittenPageNo = -1; targetBlock.EraseCount++; for (int i = 0; i < PageNoPerBlock; i++) { targetBlock.Pages[i].StreamID = FlashChipPage.PG_NOSTREAM; targetBlock.Pages[i].ValidStatus = FlashChipPage.PG_FREE; targetBlock.Pages[i].LPN = ulong.MaxValue; } #region UpdateFastGCData targetDie.BlockInfoAbstract[targetBlock.BlockID].FreePageNo += PageNoPerBlock; targetDie.BlockInfoAbstract[targetBlock.BlockID].InvalidPageNo = 0; targetDie.BlockInfoAbstract[targetBlock.BlockID].EraseCount++; #endregion if (targetDie.Status == DieStatus.Idle) { targetDie.TotalEraseExecutionPeriod += eraseLatency; } break; default: break; } OnInternalRequestServiced(targetRequest); }