/**************************************************************************** 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 ROM_D 0 /* Data in/out */ #define ROM_A 1 /* Address */ #define ROM_OE 2 /* Output enable */ #define ROM_DELAY_OED 0 /* Delay from OE to output */ #define ROM_DELAY_AD 1 /* Delay from address to output */ #define CTLSYM(c) (((c) == SYM_ONE || (c) == SYM_ZERO) ? (c) : SYM_UNKNOWN) #define max(a,b) ((a)>(b)?(a):(b)) struct rom_data { int abits; int dbits; unsigned addrMask; simTime a_time; simTime oe_time; Memory *mem; /* Actual memory data */ char *memfile; /* File to load on startup */ }; static void Rom_processEvent(SGate*,EvQueue*,SEvent*); static int Rom_checkGate(SGate*); static void Rom_initGate(EvQueue*,SGate*); static void Rom_setProp(SGate*,const char*,const void*); static void Rom_command(EvQueue*,SGate *g,const char *cmd); static Memory *Rom_getMem(SGate *); static SGateInfo rom_info = { GT_ROM, "rom",0x0, 3,{{"D",GIO_TRI,0}, {"A",GIO_IN,0}, {"OE",GIO_IN,0}}, {{"OE-D",bit(2),0}, {"A-D",bit(1),0}, {0}}, Generic_copyGate, Rom_processEvent, Rom_checkGate, Rom_initGate, Rom_setProp, Rom_command, Rom_getMem, Generic_propFrwdDelay, Generic_propBackDelay, Generic_delay, }; struct rom_data *getRomData(SGate *g) { if (!g->g_data) { struct rom_data *rd = (struct rom_data*) malloc(sizeof(struct rom_data)); g->g_data = rd; rd->mem = 0; rd->memfile = 0; rd->a_time = 0; rd->oe_time = 0; } return (struct rom_data *) g->g_data; } static void Rom_processEvent(SGate *g,EvQueue *Q,SEvent *E) { struct rom_data *rd = (struct rom_data*) g->g_data; SPort *D = g->g_ports.port[ROM_D]; SState *A = SGate_allocPortState(g,ROM_A); SState *OE = SGate_allocPortState(g,ROM_OE); SState *dout = alloc_SState(); unsigned char *d,*u; int mar_valid; /* MAR data is valid */ unsigned mar; /* The MAR */ int oe,i; int d1,d2; mar_valid = 1; SState_reinit(dout,rd->dbits); /* Process incomming events and record event times. */ if (SState_convertToInt(A,&mar) < 0) mar_valid = 0; if (E->evclass == EV_GATE) rd->a_time = Q->curStep; if (IsChangeOn(E,g,ROM_A)) rd->a_time = Q->curStep; if (IsChangeOn(E,g,ROM_OE)) rd->oe_time = Q->curStep; oe = SState_getBitSym(OE,0); oe = CTLSYM(oe); if (mar_valid && oe == SYM_ZERO) { int mdr; Memory_lookup(rd->mem,mar&rd->addrMask,&d,&u); mdr = 0; for (i = 0;i < rd->mem->nbytes;i++) mdr |= d[i] << (i<<3); if (*u) SState_unknown(dout); else SState_convertFromInt(dout,mdr); } else if (oe == SYM_ONE) SState_float(dout); else SState_unknown(dout); d1 = rd->a_time + g->g_delayParms[ROM_DELAY_AD]; d2 = rd->oe_time + g->g_delayParms[ROM_DELAY_OED]; d1 = max(d1,d2); EvQueue_setPort(Q,D,dout,d1-Q->curStep); free_SState(dout); free_SState(A); free_SState(OE); } static int Rom_checkGate(SGate *g) { SPort *A = g->g_ports.port[ROM_A]; SPort *D = g->g_ports.port[ROM_D]; SPort *OE = g->g_ports.port[ROM_OE]; if (OE->p_state.nbits != 1) { errorGate(g->g_name,"The control pin OE must 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 Rom_initGate(EvQueue *Q,SGate *g) { struct rom_data *rd = getRomData(g); rd->abits = g->g_ports.port[ROM_A]->p_net->n_nbits; rd->dbits = g->g_ports.port[ROM_D]->p_net->n_nbits; rd->addrMask = (rd->abits == SSWORDSIZE) ? SSWORDMASK : ((1<abits)-1); rd->a_time = 0; rd->oe_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 Rom_command(EvQueue *Q,SGate *g,const char *cmd) { struct rom_data *rd = (struct rom_data*) g->g_data; char fileName[STRMAX]; int r = 0; /* printf("comment Rom_command\n"); */ if (sscanf(cmd," load %[^\n]",fileName) == 1) { r = Memory_readFile(rd->mem,fileName); } else if (sscanf(cmd," dump %[^\n]",fileName) == 1) { r = Memory_writeFile(rd->mem,fileName); } else error("Unknown command received by ROM 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 Rom_setProp(SGate *g,const char *prop,const void *value) { struct rom_data *rd = getRomData(g); if (strcmp(prop,"/mem") == 0) rd->memfile = strdup((char*)value); } static Memory *Rom_getMem(SGate *g) { struct rom_data *rd = getRomData(g); return rd->mem; } void init_rom() { SGateInfo_register(&rom_info,0); }