---
# System prepended metadata

title: Highlight in RC-NVM source code
tags: [research-GraphRC]

---

# [Study] Highlight in RC-NVM source code
###### tags: `research-GraphRC`
## Introduction
[RC-NVM](https://ieeexplore.ieee.org/document/8327034) is a non-volatile memory based simulator based on [NVMain](https://ieeexplore.ieee.org/document/6296505). We acquire the source code of RC-NVM and this chapter will focus on the modification made by RC-NVM team to enable the dual-address mode (row and column) on NVMain simulator.

## RC-NVM based RRAM config
In the NVMain simulator, there's a config file specifying the configuration of the memory architecture and the electrical performance of non-volative memory cell in case the simulation target is based on NVM. Similarily, RC-NVM follows the general specification of NVMain simulator; however, some modifications have to be made in this file to enable the row-column access in RC-NVM. This file is important while decoding the underlying architecture of RC-NVM. A sample RC-NVM configuration file based on RRAM can be fonud in the following section. Notice that only architecural info is contained, electrical performance of NVM cell is tedious so excluded here.
```cpp=1
;********************************************************************************
; General memory system configuration

; Number of banks per rank 
BANKS 8

; Number of ranks per channel
RANKS 4

; Number of channels in the system
CHANNELS 2

; Number of rows in one bank
ROWS 8192 ; xx WL / macro * x vertical macros

; Number of VISIBLE columns in one LOGIC bank 
;COLS 128 ; xx bitlines/macro * xx horiz. macros / (8 device width * 8 burst cycles)
         ; should change to 1024
         ; Add another parameter, such as COLSInCacheline
COLS 1024
; COLSInCacheline 128

; whether enable sub-array level parallelism (SALP)
; options: 
;   No SALP: MATHeight = ROWS
;   SALP: number of subarrays = ROWS / MATHeight
; Assume 8 subarrays
MATHeight 1024

; RBSize - 4:1 mux (?)
;RBSize 32
RBSize 1024
CBSize 1024

; No refresh needed in RRAM
UseRefresh false
```
### Observation
This configuration file provides the architecural info:
| BANKS | RANKS | CHANNELS | ROWS | COLS | MATHeight | RBSize | CBSize |
| ----- | ----- | -------- | ---- | ---- | --------- | ------ | ------ |
| 8     | 4     | 2        | 8192 | 1024 | 1024      | 1024   | 1024   |
- BANKS, RANKS, CHANNELS: These are the standard DRAM-style architectural parameter
- ROWS: The number of rows in
- COLS: The number of columns in
- MATHeight: 
- RBSize: Row buffer size
- CBSize: Column buffer size
## Source code
### Add new instruction "CR" & "CW"
- ![](https://i.imgur.com/gdC62r4.png)
- ![](https://i.imgur.com/rKwa5Oq.png)

### New ColumnAddressMappingScheme
- ![](https://i.imgur.com/Z0bqODL.png)

### New columnDecoder
- ![](https://i.imgur.com/4lniLeq.png)
- ![](https://i.imgur.com/gg3twbw.png)

### Add Activate/Read/Write operation in Subarray level
- Decode physical address into row & col address
- ![](https://i.imgur.com/6PUHCqm.png)
- Activate row/column
- ![](https://i.imgur.com/s5AAhdp.png)
- Modify scheduling policy
- ![](https://i.imgur.com/tnkBoPp.png)

### Add Activate/Read/Write operation in Bank level
- Translate column number from physical address
- ![](https://i.imgur.com/xmn3QON.png)
- Important insight: A row/column CANNOT be activate at the same time
- ![](https://i.imgur.com/LMhQEkx.png)

### Add Column access in Rank level
- Scheduling policy
- ![](https://i.imgur.com/zbLRrRx.png)
### Memory Controller
- FindStarvedRequest
```cpp=1
bool MemoryController::FindStarvedRequest( std::list<NVMainRequest *>& transactionQueue, 
                                           NVMainRequest **starvedRequest, 
                                           SchedulingPredicate& pred )
        ...
        /* By design, mux level can only be a subset of the selected columns. */
        ncounter_t muxLevel = static_cast<ncounter_t>(col / p->RBSize);
        ncounter_t col_muxLevel = static_cast<ncounter_t>(row / p->CBSize);
        ...
```
- FindRowBufferHit
```cpp=1
bool MemoryController::FindRowBufferHit( std::list<NVMainRequest *>& transactionQueue, 
                                         NVMainRequest **hitRequest, SchedulingPredicate& pred )
        ...
        /* By design, mux level can only be a subset of the selected columns. */
        ncounter_t muxLevel = static_cast<ncounter_t>(col / p->RBSize);
        ncounter_t col_muxLevel = static_cast<ncounter_t>(row / p->CBSize);
        ...
```
- IssueMemoryCommands
```cpp=1
bool MemoryController::IssueMemoryCommands( NVMainRequest *req )
        ...
        ncounter_t muxLevel = static_cast<ncounter_t>(col / p->RBSize);
        ncounter_t col_muxLevel = static_cast<ncounter_t>(row / p->CBSize);
        ...
```
:::spoiler FindStarvedRequest(. . . . ) complete function
```cpp=1
bool MemoryController::FindStarvedRequest( std::list<NVMainRequest *>& transactionQueue, 
                                           NVMainRequest **starvedRequest, 
                                           SchedulingPredicate& pred )
{
    bool rv = false;
    std::list<NVMainRequest *>::iterator it;

    *starvedRequest = NULL;

    for( it = transactionQueue.begin(); it != transactionQueue.end(); it++ )
    {
        ncounter_t rank, bank, row, subarray, col;
        ncounter_t queueId = GetCommandQueueId( (*it)->address );

        if( !commandQueues[queueId].empty() ) continue;

        (*it)->address.GetTranslatedAddress( &row, &col, &bank, &rank, NULL, &subarray );
        
        /* By design, mux level can only be a subset of the selected columns. */
        ncounter_t muxLevel = static_cast<ncounter_t>(col / p->RBSize); /*!!!*/
        ncounter_t col_muxLevel = static_cast<ncounter_t>(row / p->CBSize); /*!!!*/

        if( !(*it)->address.IsColumnAddress()
            && activateQueued[rank][bank]
            && ( !activeSubArray[rank][bank][subarray]          /* The subarray is inactive */
                || effectiveRow[rank][bank][subarray] != row    /* Row buffer miss */
                || effectiveMuxedRow[rank][bank][subarray] != muxLevel )  /* Subset of row buffer is not at the sense amps */
            && !bankNeedRefresh[rank][bank]                     /* The bank is not waiting for a refresh */
            && !refreshQueued[rank][bank]                       /* Don't interrupt refreshes queued on bank group head. */
            && starvationCounter[rank][bank][subarray] 
                >= starvationThreshold                          /* This subarray has reached starvation threshold */
            && (*it)->arrivalCycle != GetEventQueue()->GetCurrentCycle()
            && commandQueues[queueId].empty()                   /* The request queue is empty */
            && pred( (*it) ) )                                  /* User-defined predicate is true */
        {
            *starvedRequest = (*it);
            transactionQueue.erase( it );

            /* Different row buffer management policy has different behavior */ 

            /* 
             * if Relaxed Close-Page row buffer management policy is applied,
             * we check whether there is another request has row buffer hit.
             * if not, this request is the last request and we can close the
             * row.
             */
            if(  IsLastRequest( transactionQueue, (*starvedRequest) ) )
                (*starvedRequest)->flags |= NVMainRequest::FLAG_LAST_REQUEST;

            rv = true;
            break;
        }
        else if( (*it)->address.IsColumnAddress()
            && activateQueued[rank][bank]
            && ( !activeSubArray[rank][bank][subarray]          /* The subarray is inactive */
                || effectiveCol[rank][bank][subarray] != col    /* Column buffer miss */
                || effectiveMuxedCol[rank][bank][subarray] != col_muxLevel )  /* Subset of column buffer is not at the sense amps */
            && !bankNeedRefresh[rank][bank]                     /* The bank is not waiting for a refresh */
            && !refreshQueued[rank][bank]                       /* Don't interrupt refreshes queued on bank group head. */
            && starvationCounter[rank][bank][subarray]
                >= starvationThreshold                          /* This subarray has reached starvation threshold */
            && (*it)->arrivalCycle != GetEventQueue()->GetCurrentCycle()
            && commandQueues[queueId].empty()                   /* The request queue is empty */
            && pred( (*it) ) )                                  /* User-defined predicate is true */
        {
            *starvedRequest = (*it);
            transactionQueue.erase( it );

            if(  IsLastRequest( transactionQueue, (*starvedRequest) ) )
                (*starvedRequest)->flags |= NVMainRequest::FLAG_LAST_REQUEST;

            rv = true;
            break;
        }

    }

    return rv;
}
```
:::
## Output file
### RRAM.stats
:::spoiler
```cpp=1
i0.defaultMemory.channel0.FCFS.channel0.rank0.bank0.subarray0.subArrayEnergy 243906nJ
i0.defaultMemory.channel0.FCFS.channel0.rank0.bank0.subarray0.activeEnergy 80.7128nJ
i0.defaultMemory.channel0.FCFS.channel0.rank0.bank0.subarray0.burstEnergy 5337.89nJ
i0.defaultMemory.channel0.FCFS.channel0.rank0.bank0.subarray0.writeEnergy 238487nJ
i0.defaultMemory.channel0.FCFS.channel0.rank0.bank0.subarray0.refreshEnergy 0nJ
i0.defaultMemory.channel0.FCFS.channel0.rank0.bank0.subarray0.cancelledWrites 0
i0.defaultMemory.channel0.FCFS.channel0.rank0.bank0.subarray0.cancelledWriteTime 0
i0.defaultMemory.channel0.FCFS.channel0.rank0.bank0.subarray0.pausedWrites 0
i0.defaultMemory.channel0.FCFS.channel0.rank0.bank0.subarray0.averagePausesPerRequest 0
i0.defaultMemory.channel0.FCFS.channel0.rank0.bank0.subarray0.measuredPauses 3165
i0.defaultMemory.channel0.FCFS.channel0.rank0.bank0.subarray0.averagePausedRequestProgress 0
i0.defaultMemory.channel0.FCFS.channel0.rank0.bank0.subarray0.measuredProgresses 0
i0.defaultMemory.channel0.FCFS.channel0.rank0.bank0.subarray0.reads 3379
i0.defaultMemory.channel0.FCFS.channel0.rank0.bank0.subarray0.writes 3165
i0.defaultMemory.channel0.FCFS.channel0.rank0.bank0.subarray0.activates 994
i0.defaultMemory.channel0.FCFS.channel0.rank0.bank0.subarray0.precharges 993
i0.defaultMemory.channel0.FCFS.channel0.rank0.bank0.subarray0.refreshes 0
i0.defaultMemory.channel0.FCFS.channel0.rank0.bank0.subarray0.col_reads 0
i0.defaultMemory.channel0.FCFS.channel0.rank0.bank0.subarray0.col_writes 0
i0.defaultMemory.channel0.FCFS.channel0.rank0.bank0.subarray0.col_activates 0
i0.defaultMemory.channel0.FCFS.channel0.rank0.bank0.subarray0.worstCaseEndurance 18446744073709551615
```
:::
### rram.trace
- Just memory trace