📄 ms_ldst.c
字号:
entry->invalidated = 0; entry->loadhit = NULL; vs = entry->validBytes; vs[0] = 0; vs[1] = 0; vs[2] = 0; vs[3] = 0; vs[4] = 0; vs[5] = 0; vs[6] = 0; vs[7] = 0; /* If we are allocating a load see if a previous store */ /* can provide us with a value. */ if (IsLoad(lstype)) { int off = (paddr & 7); int size = LdSizeOf(lstype); int anyhit = 0; int b, hitflag; store1 = store2 = NULL; for (entry = entry->prev; (entry); entry = prev_entry) { prev_entry = entry->prev; if (!IsStore(entry->ls->lstype)) continue; if (((entry->paddr)&~7) == (paddr&~7)) { if (store1 == NULL) store1 = entry; else { store2 = entry; break; } } } entry = st->ldst_tail; /* JEB: Address and size could be inconsistent at this point, * due to speculation. As a later enhancement, detect this * case and use this as a hint to stop fetching along this * thread, and activate a different one. Put the check earlier * in the pipeline, where the TLB translation is currently. */ if ((size+off) > 8) size = 8 - off; if (store1) { hitflag = 1; for (b = 0; b < size; b++) { if (store1->validBytes[b+off]) anyhit = 1; else { hitflag = 0; } } if (hitflag) entry->loadhit = store1; if (anyhit) return (entry); } if (store2) { hitflag = 1; for (b = 0; b < size; b++) if (!store2->validBytes[b+off]) { hitflag = 0; break; } if (hitflag) entry->loadhit = store2; } } return (entry); } /* * ldst_buffer_reserve - Reserve an entry in ldst_buffer * * Returns -1 if reservation fails */int ldst_buffer_reserve (struct s_cpu_state *st) { struct s_ldst_buffer *entry; entry = st->ldst_nextAvail; if (entry) { /* Found a free entry. Move it to the reserved */ /* list. */ st->ldst_nextAvail = entry->next; entry->next = st->ldst_nextReserved; st->ldst_nextReserved = entry; return (0); } return (-1); } /* * ldst_buffer_release - Release a reserved entry */void ldst_buffer_release (struct s_cpu_state *st) { struct s_ldst_buffer *entry = st->ldst_nextReserved; if (entry) { /* Move entry from reserved list to free list */ st->ldst_nextReserved = entry->next; entry->next = st->ldst_nextAvail; st->ldst_nextAvail = entry; }#ifdef DEBUG_CHECKS else { fprintf (stderr, "Illegal release of ldst_buffer entry\r\n"); ms_break (st, NULL, "ERR"); }#endif } /* * ldst_buffer_free - Free the given load store buffer entry */static void ldst_buffer_free (struct s_cpu_state *st, struct s_ldst_buffer *entry) { struct s_ldst_buffer *scan; /* If it's a store, check if any loads are depending */ /* on this value. Then let them know it is gone. */ if (IsStore (entry->ls->lstype)) { for (scan = st->ldst_head; (scan); scan = scan->next) { if ((scan->loadhit == entry) && IsLoad (scan->ls->lstype) ) { scan->loadhit = NULL; /* Turn off LS_ST_CACHED so */ /* it will be retried in cache */ scan->ls->status &= ~(LS_ST_PEND|LS_ST_CACHED); } } } /* Move the entry from the active list to the free list */ if (entry->prev == NULL) st->ldst_head = entry->next; else entry->prev->next = entry->next; if (entry->next == NULL) st->ldst_tail = entry->prev; else entry->next->prev = entry->prev; entry->next = st->ldst_nextAvail; st->ldst_nextAvail = entry; } /* * ldst_buffer_write - Write data into the given entry in the * load/store buffer and mark the set bytes valid. * * If invalid arguments are passed, it is due to a speculative * write. This is OK, just return silently. * * JEB: As a later enhancement, could use this as a hint to stop * fetching along this thread, and activate a different one. */static void ldst_buffer_write(struct s_cpu_state *st, struct s_ldst_buffer *entry, int paddr, char *data,int size){ int lineoffset; if (size > 8) fprintf(stderr, "Memory op large\r\n"); entry->paddr = paddr; entry->size = size; lineoffset = paddr & 7; if ((size+lineoffset) > 8) size = 8 - lineoffset; switch(size) { case 1: *(char *) (entry->data + lineoffset) = *(unsigned char*)data; *(char *) (entry->validBytes + lineoffset) = 1; break; case 2: *(char *) (entry->data + lineoffset+0) = *(unsigned char*)data; *(char *) (entry->data + lineoffset+1) = *(unsigned char*)(data+1); *(char *) (entry->validBytes + lineoffset+0) = 1; *(char *) (entry->validBytes + lineoffset+1) = 1; break; case 3: *(char *) (entry->data + lineoffset+0) = *(unsigned char*)data; *(char *) (entry->data + lineoffset+1) = *(unsigned char*)(data+1); *(char *) (entry->data + lineoffset+2) = *(unsigned char*)(data+2); *(char *) (entry->validBytes + lineoffset+0) = 1; *(char *) (entry->validBytes + lineoffset+1) = 1; *(char *) (entry->validBytes + lineoffset+2) = 1; break; case 4: if ((lineoffset & 0x03) != 0) return; *(uint *) (entry->data + lineoffset) = *(unsigned int *)data; *(uint *) (entry->validBytes + lineoffset) = 0x01010101; break; case 8: if ((lineoffset & 0x07) != 0) return; *(uint64 *) (entry->data + lineoffset) = *(uint64 *) data; *(uint64 *) (entry->validBytes + lineoffset) = ((uint64)0x01010101<<32)| (uint64 )0x01010101; break; default: fprintf(stderr, "Memory op invalid size\r\n"); break; } return;} /* * ldst_buffer_updateRead - Read data from the given entry to the * the data area pointed to, if it hit in the store buffer. * * Returns 1 when the read is satisfied from the store buffer * Otherwise returns 0. * * If invalid arguments are passed, it is due to a speculative * load. This is OK, just return silently. * * JEB: As a later enhancement, could use this as a hint to stop * fetching along this thread, and activate a different one. */static intldst_buffer_updateRead(struct s_cpu_state *st, struct s_ldst_buffer *entry, int paddr, char *data, int size){ int lineoffset, i; char vb[8]; struct s_ldst_buffer *store_entry; if (entry->loadhit == NULL) return (0); vb[0] = vb[1] = vb[2] = vb[3] = vb[4] = vb[5] = vb[6] = vb[7] = 0; lineoffset = paddr & 7; if ((size+lineoffset) > 8) size = 8 - lineoffset; /* Update this entry from the store */ store_entry = entry->loadhit; for (i = 0; i < size; i++) { if (*(char *) (store_entry->validBytes + lineoffset+i) == 1) { data[i] = *(char *) (store_entry->data + lineoffset+i); vb[i+lineoffset] = 1; } } for (i = 0; i < size; i++) { lineoffset = paddr & 7; if (vb[i+lineoffset] == 0) { /* Didn't update it. */ return 0; } } return 1;} /* * ldst_retire_stores - Retire unspeculative stores (for imprecise * CPU model) */static void ldst_retire_stores (struct s_cpu_state *st) { struct s_ldst_buffer *entry, *next_entry; struct s_lsq *ls; int inum, ret; INST *ip; next_entry = 0; /* Slience bogus compiler error message */ for (entry = st->ldst_head; (entry); entry = next_entry) { next_entry = entry->next; ls = entry->ls; if (IsLoad (ls->lstype) || IsPrefetch(ls->lstype)) continue; if ((ls->status & LS_ST_DONE) == 0) continue; inum = ls->inum; ip = &st->iwin[inum]; /* Uncached loads don't need any more */ /* processing, just release the entry. */ if (ls->status & LS_ST_UNCACHED) { if (st->iwin_flags[inum] & IWIN_LDSTBUF) { st->iwin_flags [inum] &= ~IWIN_LDSTBUF; ldst_buffer_free (st, entry); }#ifdef DEBUG_CHECKS if (st->iwin_flags[inum] & IWIN_SQUASH) { fprintf (stderr, "Executing squashed load/store\r\n"); ms_break (st, NULL, "ERR"); }#endif /* DEBUG_CHECKS */ if (ip->r1 > 0) reg_writeback ((void *)st, (void *)ip->r1); else free_inst (st, inum); continue; } if ((st->iwin_flags[inum] & (IWIN_STORE | IWIN_SPEC)) == IWIN_STORE) { /* Found a store that is no longer speculative, */ /* so process it. */#ifdef DEBUG_CHECKS if (st->iwin_flags[inum] & IWIN_SQUASH) { fprintf (stderr, "Executing squashed load/store\r\n"); ms_break (st, NULL, "ERR"); }#endif /* DEBUG_CHECKS */ ret = ldst_buffer_retire (st, inum); if (ret < 0) /* Retry the store if the */ /* line has been evicted. */ ls->status &= ~(LS_ST_CACHED | LS_ST_DONE); else if (ret == 0) { /* It worked, can free this */ /* instruction. */ if (ip->r1 > 0) reg_writeback ((void *)st, (void *)ip->r1); else free_inst (st, inum); } else ; /* Still waiting for the line */ /* to come in, try again next */ /* cycle. */ } } } /* * ldst_buffer_retire - Do actual writes to cache as stores * graduate. * * Returns 0 if successful * Returns 1 if the line hasn't come into the cache yet * Returns -1 if the line has been evicted (=> need to retry) */int ldst_buffer_retire(struct s_cpu_state *st, int inum){ struct s_ldst_buffer *entry = st->inum2ldst[inum];#ifdef DEBUG_CHECKS if (st->iwin_flags[inum] & IWIN_SQUASH) { fprintf (stderr, "Executing squashed load/store\r\n"); ms_break (st, NULL, "ERR"); }#endif /* DEBUG_CHECKS */ if (entry->ls->inum != inum) { fprintf(stderr, "retire failure in ldst_buffer_retire\r\n"); ms_break (st, NULL, "ERR"); } if (entry->ls->status & LS_ST_UNCACHED) goto retire_exit; if (IsPrefetch(entry->ls->lstype)) goto retire_exit; if (entry->invalidated) { /* Line was nuked from the cache */ char *dataPtr; int ret; if (IsLoad(entry->ls->lstype) || (entry->ls->lstype == ST_INTEGER_SC)) { IncStat(ST_LDST_INVALIDLOAD); return -1; /* Fail loads or SCs */ } /* Refetch line for stores. */ if (entry->dataPtr == NULL) { IncStat(ST_LDST_WAIT); /* Outstanding memory op - must wait for it to finish */ return 1; } st->ms_action = ACT_DCACHE_MISS; /* Update Mipsy PC so memstat knows where miss came from. */ ((CPUState *) (st->mipsyPtr))->PC = st->iwin_pc[entry->ls->inum]; ret = DCacheFetchExclusive(CPUNUM(st), entry->ls->addr, entry->ls->paddr,0, &dataPtr); switch (ret) { case SUCCESS: entry->dataPtr = dataPtr; /* Still in cache */ IncStat(ST_LDST_REFETCH); break; case FAILURE: /* If we got invalidated then most likley we are not in the * second level cache. Make this report as second level Dcache * miss. */ entry->cacheStallReason = E_L2 | E_D; /* Cache couldn't accept the request */ IncStat(ST_LDST_WAIT); return 1; /* Retry latter. */ case STALL: /* Memory system has it down */ entry->missTag = (void *) dataPtr; entry->cacheStallReason = MxsClassifyMiss(CPUNUM(st), entry->ls->addr, entry->ls->paddr, FALSE); entry->dataPtr = NULL; entry->invalidated = 0; IncStat(ST_LDST_REFETCH); return 1; } } if ((entry->dataPtr == NULL) && /* Data not here yet. */ (entry->ls->lstype != ST_INTEGER_SC)) { /* OK for failed SCs */ IncStat(ST_LDST_WAIT); return 1; } if (IsStore(entry->ls->lstype)) { int off = (entry->paddr&7); char *dst = (char *)((uint)entry->dataPtr&~7) + off; char *src = entry->data + off; IncStat(ST_LDST_RETIRE_STORE);#ifdef TRACE if (tracefile) { struct s_trace trc; trc.addr = entry->ls->addr; trc.lstype = entry->ls->lstype; trc.u.dreg = 0.0; bcopy (src, (char *)&trc.u.dreg, entry->size); fwrite (&trc, sizeof (struct s_trace), 1, tracefile); fflush (tracefile); }#endif switch (entry->size) { case 0: break; case 1: dst[0] = src[0]; break; case 2: dst[0] = src[0]; dst[1] = src[1]; break; case 3: dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; break; case 4: ((int *)dst)[0] = ((int *)src)[0]; break; case 8: ((double *)dst)[0] = ((double *)src)[0]; break; default: bcopy(src,dst, entry->size); } } else { IncStat(ST_LDST_RETIRE_LOAD);#ifdef TRACE if (tracefile) { struct s_trace trc; trc.addr = entry->ls->addr; trc.lstype = entry->ls->lstype; trc.u.dreg = 0.0; trc.u.ireg = entry->ls->reg; if (!trace_writes) { fwrite (&trc, sizeof (struct s_trace), 1, tracefile); fflush (tracefile); } }#endif }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -