// IEC Send byte standard function // // Sends the byte and can signal EOI // boolean IEC::sendByte(byte data, boolean signalEOI) { // Listener must have accepted previous data if(timeoutWait(m_dataPin, true)) return false; // Say we're ready writeCLOCK(false); // Wait for listener to be ready if(timeoutWait(m_dataPin, false)) return false; if(signalEOI) { // TODO: Make this like sd2iec and may not need a fixed delay here. // Signal eoi by waiting 200 us delayMicroseconds(TIMING_EOI_WAIT); // get eoi acknowledge: if(timeoutWait(m_dataPin, true)) return false; if(timeoutWait(m_dataPin, false)) return false; } delayMicroseconds(TIMING_NO_EOI); // Send bits for(byte n = 0; n < 8; n++) { // TODO: Here check whether data pin goes low, if so end (enter cleanup)! writeCLOCK(true); // set data writeDATA((data bitand 1) ? false : true); delayMicroseconds(TIMING_BIT); writeCLOCK(false); delayMicroseconds(TIMING_BIT); data >>= 1; } writeCLOCK(true); writeDATA(false); // TODO: Maybe make the following ending more like sd2iec instead. // Line stabilization delay delayMicroseconds(TIMING_STABLE_WAIT); // Wait for listener to accept data if(timeoutWait(m_dataPin, true)) return false; return true; } // sendByte
void X86::declareMatrix(int decl_type, int type, string name, list<string> dims) { int size = 1; for(list<string>::iterator it = dims.begin(); it != dims.end(); it++) { size *= atoi((*it).c_str()); } if(decl_type == VAR_GLOBAL) { stringstream s; switch(type) { case TIPO_INTEIRO: case TIPO_REAL: case TIPO_CARACTERE: case TIPO_LOGICO: case TIPO_LITERAL: s << X86::makeID(name) << " times " << size << " dd 0"; break; default: GPTDisplay::self()->showError("Erro interno: tipo nao suportado (X86::declarePrimitive)."); exit(1); } writeDATA(s.str()); } else if(decl_type == VAR_PARAM) { _subprograms[currentScope()].declareParam(name, type, size); } else if(decl_type == VAR_LOCAL) { _subprograms[currentScope()].declareLocal(name, size); } else { GPTDisplay::self()->showError("Erro interno: X86::declareMatrix)."); exit(1); } }
byte IEC::timeoutWait(byte waitBit, boolean whileHigh) { word t = 0; boolean c; while(t < TIMEOUT) { // Check the waiting condition: c = readPIN(waitBit); if(whileHigh) c = not c; if(c) return false; delayMicroseconds(2); // The aim is to make the loop at least 3 us t++; } // If down here, we have had a timeout. // Release lines and go to inactive state with error flag writeCLOCK(false); writeDATA(false); m_state = errorFlag; // Wait for ATN release, problem might have occured during attention while(!readATN()); // Note: The while above is without timeout. If ATN is held low forever, // the CBM is out in the woods and needs a reset anyways. return true; } // timeoutWait
string X86::addGlobalLiteral(string str) { stringstream s; string lb = createLabel(false, "str"); s << lb << " db '" << toNasmString(str) << "',0"; writeDATA(s.str()); return lb; }
void X86::declarePrimitive(int decl_type, const string& name, int type) { stringstream s; if(decl_type == VAR_GLOBAL) { //all sizes have 32 bits (double word) switch(type) { case TIPO_INTEIRO: case TIPO_REAL: case TIPO_CARACTERE: case TIPO_LITERAL: case TIPO_LOGICO: s << X86::makeID(name) << " dd 0"; writeDATA(s.str()); break; default: GPTDisplay::self()->showError("Erro interno: tipo nao suportado (X86::declarePrimitive)."); exit(1); } } else if(decl_type == VAR_PARAM) { _subprograms[currentScope()].declareParam(name, type); } else if(decl_type == VAR_LOCAL) { _subprograms[currentScope()].declareLocal(name); } else { GPTDisplay::self()->showError("Erro interno: X86::declarePrimitive)."); exit(1); } }
//------------------------------------------------------------------------------------------------------------------- void bytebuffer::writeUSTRING(const wchar_t* string) { unsigned int size; for(size = 0;string[size] != 0;size++) ; writeINT(size); writeDATA((char*)string,size *2); }
//------------------------------------------------------------------------------------------------------------------- void bytebuffer::writeASTRING(const char* string) { unsigned int size; for(size = 0;string[size] != '\0';size++) ; writeSHORT(size); writeDATA(string,size); }
//------------------------------------------------------------------------------------------------------------------- void bytebuffer::writeUSTRING(const char* string) { unsigned int size; for(size = 0;string[size] != '\0';size++) ; wchar_t* new_string = new wchar_t[size]; ascii_to_unicode(new_string,string,size); writeINT(size); writeDATA((char*)new_string,size *2); delete [] new_string; }
//------------------------------------------------------------------------------------------------------------------- void bytebuffer::writeASTRING(const wchar_t* string) { unsigned int size; for(size = 0;string[size] != 0;size++) ; char* new_string = new char[size]; unicode_to_ascii(new_string,string,size); writeSHORT(size); writeDATA(new_string,size); delete [] new_string; }
// A special send command that informs file not found condition // boolean IEC::sendFNF() { // Message file not found by just releasing lines writeDATA(false); writeCLOCK(false); // Hold back a little... delayMicroseconds(TIMING_FNF_DELAY); return true; } // sendFNF
// this routine will set the direction on the bus back to normal // (the way it was when the computer was switched on) boolean IEC::undoTurnAround(void) { writeDATA(true); delayMicroseconds(TIMING_BIT); writeCLOCK(false); delayMicroseconds(TIMING_BIT); // wait until the computer releases the clock line if(timeoutWait(m_clockPin, true)) return false; return true; } // undoTurnAround
// IEC turnaround boolean IEC::turnAround(void) { // Wait until clock is released if(timeoutWait(m_clockPin, false)) return false; writeDATA(false); delayMicroseconds(TIMING_BIT); writeCLOCK(true); delayMicroseconds(TIMING_BIT); return true; } // turnAround
void IEC::testOUTPUTS() { static bool lowOrHigh = false; unsigned long now = millis(); // switch states every second. if(now - m_lastMillis >= 1000) { m_lastMillis = now; char buffer[80]; sprintf(buffer, "Lines: CLOCK: %s DATA: %s", (lowOrHigh ? "HIGH" : "LOW"), (lowOrHigh ? "HIGH" : "LOW")); Log(Information, FAC_IEC, buffer); writeCLOCK(lowOrHigh); writeDATA(lowOrHigh); lowOrHigh ^= true; } } // testOUTPUTS
string X86::source() { stringstream str; //.data footer writeDATA("datasize equ $ - data_no"); str << _head.str() << _bss.str() << _data.str(); //.text header str << "section .text" << endl; str << "start_no equ $" << endl; string sss; for(map<string, X86SubProgram>::iterator it = _subprograms.begin(); it != _subprograms.end(); ++it) { sss = it->second.source(); str << it->second.source(); } str << _lib.str(); return str.str(); }
// This function checks and deals with atn signal commands // // If a command is recieved, the cmd-string is saved in cmd. Only commands // for *this* device are dealt with. // // Return value, see IEC::ATNCheck definition. IEC::ATNCheck IEC::checkATN(ATNCmd& cmd) { ATNCheck ret = ATN_IDLE; byte i = 0; if(not readATN()) { // Attention line is active, go to listener mode and get message writeDATA(true); writeCLOCK(false); #ifdef CONSOLE_DEBUG //Log(Information, FAC_IEC, "ATT.ACTIVE"); #endif delayMicroseconds(TIMING_ATN_PREDELAY); // Get first ATN byte, it is either LISTEN or TALK ATNCommand c = (ATNCommand)receiveByte(); if(m_state bitand errorFlag) return ATN_ERROR; if(c == (ATN_CODE_LISTEN bitor m_deviceNumber)) { // Okay, we will listen. #ifdef CONSOLE_DEBUG //Log(Information, FAC_IEC, "LISTEN"); #endif // Get the first cmd byte, the cmd code c = (ATNCommand)receiveByte(); if (m_state bitand errorFlag) return ATN_ERROR; //Log(Information, FAC_IEC, "CODE"); cmd.code = c; if((c bitand 0xF0) == ATN_CODE_DATA) { // A heapload of data might come now, client handles this //Log(Information, FAC_IEC, "LDATA"); ret = ATN_CMD_LISTEN; } else if(c not_eq ATN_CODE_UNLISTEN) { #ifdef CONSOLE_DEBUG //Log(Information, FAC_IEC, "CMD"); #endif // Some other command. Record the cmd string until UNLISTEN is send for(;;) { c = (ATNCommand)receiveByte(); if(m_state bitand errorFlag) return ATN_ERROR; if((m_state bitand atnFlag) and (c == ATN_CODE_UNLISTEN)) break; if(i >= ATN_CMD_MAX_LENGTH) { // Buffer is going to overflow, this is an error condition return ATN_ERROR; } cmd.str[i++] = c; } ret = ATN_CMD; } } else if (c == (ATN_CODE_TALK bitor m_deviceNumber)) { // Okay, we will talk soon, record cmd string while ATN is active #ifdef CONSOLE_DEBUG //Log(Information, FAC_IEC, "TALK"); #endif // First byte is cmd code c = (ATNCommand)receiveByte(); if(m_state bitand errorFlag) return ATN_ERROR; cmd.code = c; while(not readATN()) { if(readCLOCK()) { c = (ATNCommand)receiveByte(); if(m_state bitand errorFlag) return ATN_ERROR; if(i >= ATN_CMD_MAX_LENGTH) { // Buffer is going to overflow, this is an error condition return ATN_ERROR; } cmd.str[i++] = c; } } // Now ATN has just been released, do bus turnaround if(!turnAround()) return ATN_ERROR; // We have recieved a CMD and we should talk now: ret = ATN_CMD_TALK; } else { // Either the message is not for us or insignificant, like unlisten. delayMicroseconds(TIMING_ATN_DELAY); writeDATA(false); writeCLOCK(false); // { // char buffer[20]; // sprintf(buffer, "NOTUS: %u", c); // Log(Information, FAC_IEC, buffer); // } // Wait for ATN to release and quit while(not readATN()); //Log(Information, FAC_IEC, "ATNREL"); } } else { // No ATN, release lines writeDATA(false); writeCLOCK(false); } // some delay is required before more ATN business delayMicroseconds(TIMING_ATN_DELAY); cmd.strlen = i; return ret; } // checkATN
// IEC Recieve byte standard function // // Returns data recieved // Might set flags in iec_state // // TODO: m_iec might be better returning bool and returning read byte as reference in order to indicate any error. byte IEC::receiveByte(void) { m_state = noFlags; // Wait for talker ready if(timeoutWait(m_clockPin, false)) { #ifdef CONSOLE_DEBUG // Log(Information, FAC_IEC, "T1"); #endif return 0; } // Say we're ready writeDATA(false); // Record how long CLOCK is high, more than 200 us means EOI byte n = 0; while(readCLOCK() and (n < 20)) { delayMicroseconds(10); // this loop should cycle in about 10 us... n++; } if(n >= TIMING_EOI_THRESH) { // EOI intermission m_state or_eq eoiFlag; // Acknowledge by pull down data more than 60 us writeDATA(true); delayMicroseconds(TIMING_BIT); writeDATA(false); // but still wait for clk if(timeoutWait(m_clockPin, true)) { #ifdef CONSOLE_DEBUG // Log(Information, FAC_IEC, "T2"); #endif return 0; } } // Sample ATN if(false == readATN()) m_state or_eq atnFlag; byte data = 0; // Get the bits, sampling on clock rising edge: for(n = 0; n < 8; n++) { data >>= 1; if(timeoutWait(m_clockPin, false)) { #ifdef CONSOLE_DEBUG // Log(Information, FAC_IEC, "T3"); #endif return 0; } data or_eq (readDATA() ? (1 << 7) : 0); if(timeoutWait(m_clockPin, true)) { #ifdef CONSOLE_DEBUG // Log(Information, FAC_IEC, "T4"); #endif return 0; } } // Signal we accepted data: writeDATA(true); return data; } // receiveByte
//------------------------------------------------------------------------------------------------------------------- void bytebuffer::writeBUFFER(bytebuffer *data) { writeDATA(data->getBuffer(),data->getSize()); }