/**************************************************************************** Copyright (C) 1987-2005 by Jeffery P. Hansen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ****************************************************************************/ #include #include #include #include "gsim.h" #define RAM_D 0 /* Data in/out */ #define RAM_A 1 /* Address */ #define RAM_CS 2 /* Chip select */ #define RAM_WE 3 /* Write enable */ #define RAM_OE 4 /* Output enable */ #define RSO_NOP 0 /* Do not modify memory */ #define RSO_XSTORE 1 /* Store unknown value at address */ #define RSO_DSTORE 2 /* Store data value at address */ #define RSO_WIPE 3 /* Invalidate all memory locs. */ #define ROO_DATA 0 /* Output addressed data */ #define ROO_ZDATA 1 /* Output float */ #define ROO_XDATA 2 /* Output unknown */ #define RAM_DELAY_OED 0 /* Delay from OE to output */ #define RAM_DELAY_CSD 1 /* Delay from CS to output */ #define RAM_DELAY_AD 2 /* Delay from address to output */ #define RAM_DELAY_ADDRSETUP 3 /* Setup time for address */ #define RAM_DELAY_DATASETUP 4 /* Setup time for data */ #define RAM_DELAY_ADDRHOLD 5 /* Hold time for address */ #define RAM_DELAY_DATAHOLD 6 /* Hold time for data */ #define max(a,b) ((a)>(b)?(a):(b)) #define sp(a,b) (((a)<<8)|(b)) #define CODE(c) ((c) == SYM_ONE ? 1 : ((c) == SYM_ZERO ? 0 : -1)) #define CTLSYM(c) (((c) == SYM_ONE || (c) == SYM_ZERO) ? (c) : SYM_UNKNOWN) struct ram_data { int abits; /* # bits in address */ int dbits; /* # bits in data */ unsigned addrMask; /* Mask to select address bits */ simTime a_time; /* Time of last addr change */ simTime d_time; /* Time of last data change */ simTime oe_time; /* Time of last data change */ simTime cs_time; /* Time of last data change */ simTime we_time; /* Time of last data change */ simTime store_time; /* Time memory was written */ int is_stable; /* Memory has stablized at least once */ Memory *mem; /* Actual memory data */ char *memfile; /* File to load on startup */ }; static void Ram_processEvent(SGate*,EvQueue*,SEvent*); static int Ram_checkGate(SGate*); static void Ram_initGate(EvQueue*,SGate*); static void Ram_setProp(SGate*,const char*,const void*); static void Ram_command(EvQueue*,SGate*,const char*); static Memory *Ram_getMem(SGate*); static SGateInfo ram_info = { GT_RAM, "ram",0x0, 5,{{"D",GIO_INOUT,0}, {"A",GIO_IN,0}, {"CS",GIO_IN,0}, {"WE",GIO_IN,0}, {"OE",GIO_IN,0}}, {{"OE-D",0,-1}, {"CS-D",0,-1}, {"A-D",0,-1}, {"addr_setup",0,-1}, {"data_setup",0,-1}, {"addr_hold",0,-1}, {"data_hold",0,-1}, {0}}, Generic_copyGate, Ram_processEvent, Ram_checkGate, Ram_initGate, Ram_setProp, Ram_command, Ram_getMem, Generic_propFrwdDelay, Generic_propBackDelay, Generic_delay, }; struct ram_data *getRamData(SGate *g) { if (!g->g_data) { struct ram_data *rd = (struct ram_data*) malloc(sizeof(struct ram_data)); g->g_data = rd; rd->mem = 0; rd->memfile = 0; rd->a_time = 0; rd->oe_time = 0; rd->is_stable = 0; } return (struct ram_data *) g->g_data; } static void Ram_processEvent(SGate *g,EvQueue *Q,SEvent *E) { struct ram_data *rd = (struct ram_data*) g->g_data; SPort *D = g->g_ports.port[RAM_D]; SState *A = SGate_allocPortState(g,RAM_A); SState *CS = SGate_allocPortState(g,RAM_CS); SState *OE = SGate_allocPortState(g,RAM_OE); SState *WE = SGate_allocPortState(g,RAM_WE); unsigned char *d,*u; int oop,wop; int mar_valid; /* MAR data is valid */ int mdr_valid; /* MDR data is valid */ int mar_setup; /* Setup time has elapsed for MAR data */ int mdr_setup; /* Setup time has elapsed for MDR data */ unsigned mar,mdr; /* The MAR and MDR */ int oe,cs,we; int i; SState *dout = alloc_SState(); int d1,d2,d3; mar_valid = mdr_valid = 1; mar_setup = mdr_setup = 1; /* * Don't process memory events until inputs have stablized at least once. */ if (!rd->is_stable) { if (SState_isLogic(A) && SState_isLogic(CS) && SState_isLogic(OE) && SState_isLogic(WE)) rd->is_stable = 1; else { return; } } SState_reinit(dout,rd->dbits); /* Process incomming events and record event times. */ if (SState_convertToInt(&D->p_net->n_state,&mdr) < 0) mdr_valid = 0; if (SState_convertToInt(A,&mar) < 0) mar_valid = 0; if (E->evclass == EV_GATE) rd->a_time = Q->curStep; if (IsChangeOn(E,g,RAM_A)) rd->a_time = Q->curStep; if (IsChangeOn(E,g,RAM_D)) rd->d_time = Q->curStep; if (IsChangeOn(E,g,RAM_CS)) rd->cs_time = Q->curStep; if (IsChangeOn(E,g,RAM_OE)) rd->oe_time = Q->curStep; if (IsChangeOn(E,g,RAM_WE)) rd->we_time = Q->curStep; oe = SState_getBitSym(OE,0); oe = CTLSYM(oe); cs = SState_getBitSym(CS,0); cs = CTLSYM(cs); we = SState_getBitSym(WE,0); we = CTLSYM(we); if (rd->a_time + g->g_delayParms[RAM_DELAY_ADDRSETUP] > Q->curStep) mar_setup = 0; if (rd->d_time + g->g_delayParms[RAM_DELAY_DATASETUP] > Q->curStep) mdr_setup = 0; /* printf("comment mem: oe=%d cs=%d we=%d\n",oe,cs,we); */ /* Select the memory store mode */ switch (sp(cs,we)) { case sp(SYM_ZERO,SYM_ZERO) : /* Standard write operation */ if (mar_valid && mar_setup) { /* Address line is valid */ if (mdr_valid) wop = RSO_DSTORE; /* Data is valid */ else wop = RSO_XSTORE; /* Data is invalid */ } else wop = RSO_WIPE; /* Oops address line is unknown */ break; case sp(SYM_ONE,SYM_ZERO) : case sp(SYM_ONE,SYM_UNKNOWN) : case sp(SYM_ONE,SYM_ONE) : case sp(SYM_ZERO,SYM_ONE) : case sp(SYM_UNKNOWN,SYM_ONE) : wop = RSO_NOP; /* No write operation */ break; default : /* Write line status unknown */ if (mar_valid && mar_setup) wop = RSO_XSTORE; /* If address was valid, store X */ else wop = RSO_WIPE; /* Oops address line is unknown */ } /* Select the memory store output mode */ switch (sp(cs,oe)) { case sp(SYM_ZERO,SYM_ZERO) : if (mar_valid) oop = ROO_DATA; else oop = ROO_XDATA; break; case sp(SYM_ONE,SYM_ZERO) : case sp(SYM_ONE,SYM_UNKNOWN) : case sp(SYM_ONE,SYM_ONE) : case sp(SYM_ZERO,SYM_ONE) : case sp(SYM_UNKNOWN,SYM_ONE) : oop = ROO_ZDATA; break; default : oop = ROO_XDATA; } if (wop == RSO_WIPE) oop = ROO_XDATA; if (mar_valid) Memory_lookup(rd->mem,mar&rd->addrMask,&d,&u); switch (wop) { case RSO_XSTORE : /* printf("comment mem: store unknown\n"); */ *u = 1; break; case RSO_DSTORE : /* printf("comment mem: store data %x @ %x\n",mdr,mar); */ for (i = 0;i < rd->mem->nbytes;i++) d[i] = 0xff & (mdr >> (i<<3)); *u = 0; break; case RSO_WIPE : /* printf("comment mem: erase all\n"); */ #if 0 Memory_flush(rd->mem); #endif sendMsg("simerror Write to unknown address on memory '%s'.",g->g_name); Q->flags &= ~(EVF_RUN|EVF_PERSRUN); break; } switch (oop) { case ROO_DATA : if (*u) { SState_unknown(dout); /* printf("comment mem: output unknown @ %x\n",mar); */ } else { mdr = 0; for (i = 0;i < rd->mem->nbytes;i++) mdr |= d[i] << (i<<3); SState_convertFromInt(dout,mdr); /* printf("comment mem: output %x @ %x\n",mdr,mar); */ } break; case ROO_XDATA : /* printf("comment mem: output unknown\n"); */ SState_unknown(dout); break; case ROO_ZDATA : /* printf("comment mem: output float\n"); */ SState_float(dout); break; } d1 = rd->a_time + g->g_delayParms[RAM_DELAY_AD]; d2 = rd->oe_time + g->g_delayParms[RAM_DELAY_OED]; d3 = rd->cs_time + g->g_delayParms[RAM_DELAY_CSD]; d1 = max(d1,d2); d1 = max(d1,d3); EvQueue_setPort(Q,D,dout,d1-Q->curStep); free_SState(dout); free_SState(A); free_SState(CS); free_SState(OE); free_SState(WE); } static int Ram_checkGate(SGate *g) { SPort *A = g->g_ports.port[RAM_A]; SPort *D = g->g_ports.port[RAM_D]; SPort *CS = g->g_ports.port[RAM_CS]; SPort *WE = g->g_ports.port[RAM_WE]; SPort *OE = g->g_ports.port[RAM_OE]; if (CS->p_state.nbits != 1 || WE->p_state.nbits != 1 || OE->p_state.nbits != 1) { errorGate(g->g_name,"The control pins CS, WE and OE must all be single-bit."); return -1; } if (A->p_state.nbits > 32) { errorGate(g->g_name,"Addresses greater than 32 bits are not supported."); return -1; } if (D->p_state.nbits > 32) { errorGate(g->g_name,"Data lines greater than 32 bits are not supported."); return -1; } return 0; } static void Ram_initGate(EvQueue *Q,SGate *g) { struct ram_data *rd = getRamData(g); g->g_data = rd; rd->abits = g->g_ports.port[RAM_A]->p_net->n_nbits; rd->dbits = g->g_ports.port[RAM_D]->p_net->n_nbits; rd->addrMask = (rd->abits == SSWORDSIZE) ? SSWORDMASK : ((1<abits)-1); rd->a_time = 0; rd->d_time = 0; rd->oe_time = 0; rd->cs_time = 0; rd->we_time = 0; rd->mem = new_Memory(rd->abits,rd->dbits); if (rd->memfile) { int r = Memory_readFile(rd->mem,rd->memfile); if (r < 0) { error("Unable to open memory file '%s' for load or dump.",rd->memfile); } else if (r > 0) { error("Syntax error in memory file '%s'.",rd->memfile); } } } static void Ram_command(EvQueue *Q,SGate *g,const char *cmd) { struct ram_data *rd = (struct ram_data*) g->g_data; char fileName[STRMAX]; int r = 0; if (sscanf(cmd," load %[^\n]",fileName) == 1) { r = Memory_readFile(rd->mem,fileName); EvQueue_qGateEv(Q,g,0,0,0); } else if (sscanf(cmd," dump %[^\n]",fileName) == 1) { r = Memory_writeFile(rd->mem,fileName); } else error("Unknown command received by RAM element."); if (r < 0) { error("Unable to open memory file '%s' for load or dump.",fileName); } else if (r > 0) { error("Syntax error in memory file '%s'.",fileName); } } static void Ram_setProp(SGate *g,const char *prop,const void *value) { struct ram_data *rd = getRamData(g); if (strcmp(prop,"/mem") == 0) rd->memfile = strdup((char*)value); } static Memory *Ram_getMem(SGate *g) { struct ram_data *rd = getRamData(g); return rd->mem; } void init_ram() { SGateInfo_register(&ram_info,0); }