while(Serial.available()) stops after constant number of bytes

Hi!

I'm working on quite a big project to drive Z80 CPU. I have a problem with sending hex file into atmega's memory:

void loop() {
  //Needed for LCD?
  __builtin_avr_delay_cycles (4);

  if(clkInternal){
    while(micros() < nextHalfTick){;}
    
    //TODO: port mnipulation
    digitalWrite(Z80_PIN_CLK, LOW);
    //readSerialInput();  //read Serial only between ticks
    while(Serial.available()){
      //Serial.println();
      char c = Serial.read();
      //Serial.println(c);
      cumulateSerial(c);
      delayMicroseconds(150);
    }
void cumulateSerial(char c){
  //char c = Serial.read();

//  Serial.println();
//  Serial.print(F("Got new sign: "));
  Serial.print(c);
//  Serial.print(F(" 0x"));
//  Serial.println(c, HEX);

  //return;
  //TODO : convChar()

  // On carriage return, process the received data.
  if (c == '\r' || c == '\n' || c == ' ') {
      // Properly terminate the string.
      serialBuffer[serialStringLength] = '\0';
      if(serialStringLength > 0){
        Serial.print(F("serialBuffer: "));
        Serial.println(serialBuffer);
        readSerialInput();
      }
      serialStringLength = 0;
      //Serial.println(F("End of string."));
  }

  // Otherwise buffer the incoming byte.
  else if (c > ' ' && c < 127) {
    if(serialStringLength < SERIAL_BUFFER_SIZE - 1){
      Serial.print(F("Add to string: "));
      Serial.println(c);
      serialBuffer[serialStringLength++] = c;
    }else{
      Serial.println(F("sSL overload!"));
    }
      //Serial.println(F("Cumulate."));
  }
}

Sent command:
:2000000099001122334455667788AABBCCDDEEFF99001122334455667788AABBCCDDEEFF99

Result i get:

[15:53:19:509]  [some text from other part of program]
[15:53:19:514] 
[15:53:19:861] :Add to string: :
[15:53:19:861] 2Add to string: 2
[15:53:19:867] 0Add to string: 0
[15:53:19:867] 0Add to string: 0
[15:53:19:867] 0Add to string: 0
[15:53:19:867] 0Add to string: 0
[15:53:19:879] 0Add to string: 0
[15:53:19:879] 0Add to string: 0
[15:53:19:879] 0Add to string: 0
[15:53:19:879] 9Add to string: 9
[15:53:19:879] 9Add to string: 9
[15:53:19:879] 0Add to string: 0
[15:53:19:888] 0Add to string: 0
[15:53:19:888] 1Add to string: 1
[15:53:19:888] 1Add to string: 1
[15:53:19:888] 2Add to string: 2
[15:53:19:888] 2Add to string: 2
[15:53:19:888] 3Add to string: 3
[15:53:19:899] 3Add to string: 3
[15:53:19:899] 4Add to string: 4
[15:53:19:899] 4Add to string: 4
[15:53:19:899] 5Add to string: 5
[15:53:19:899] 5Add to string: 5
[15:53:19:899] 6Add to string: 6
[15:53:19:910] 6Add to string: 6
[15:53:19:910] 7Add to string: 7
[15:53:19:910] 7Add to string: 7
[15:53:19:910] 8Add to string: 8
[15:53:19:910] 8Add to string: 8
[15:53:19:910] AAdd to string: A
[15:53:19:918] AAdd to string: A
[15:53:19:918] BAdd to string: B
[15:53:19:918] BAdd to string: B
[15:53:19:918] CAdd to string: C
[15:53:19:918] CAdd to string: C
[15:53:19:925] DAdd to string: D
[15:53:19:925] DAdd to string: D
[15:53:19:925] EAdd to string: E
[15:53:19:925] EAdd to string: E
[15:53:19:925] FAdd to string: F
[15:53:19:930] FAdd to string: F
[15:53:19:930] 9Add to string: 9
[15:53:19:935] 9Add to string: 9
[15:53:19:935] 0Add to string: 0
[15:53:19:935] 0Add to string: 0
[15:53:19:939] 1Add to string: 1
[15:53:19:939] 1Add to string: 1
[15:53:19:939] 2Add to string: 2
[15:53:19:945] 2Add to string: 2
[15:53:19:945] 3Add to string: 3
[15:53:19:945] 3Add to string: 3
[15:53:19:949] 4Add to string: 4
[15:53:19:949] 4Add to string: 4
[15:53:19:949] 5Add to string: 5
[15:53:19:953] 5Add to string: 5
[15:53:19:953] 6Add to string: 6
[15:53:19:957] 6Add to string: 6
[15:53:19:957] 7Add to string: 7
[15:53:19:962] 7Add to string: 7
[15:53:19:962] 8Add to string: 8
[15:53:19:962] 8Add to string: 8
[15:53:19:966] AAdd to string: A
[15:53:19:966] AAdd to string: A
[15:53:19:969] [some text from other part of program]

As You can see, I tried to debug it in many ways, but cannot find the problem.
I'm working on atmega8a. As i tested it long time ago (but not the same program), It worked well...

Is there anything obvious I'm missing?

Best regards!

The rest of your code.

Sixty three characters is suspicious given the size of the input buffer. I suspect that you're not reading the incoming stream in a timely fashion and the remainder are discarded.

It's big so I hoped it can be avoided. It's a work in progress obviously.
Some parts are speed-sensitive (everything around mute()).
The program is split onto three separate files:

main:

//multiplexer PD4-PD7
//#define MULTI_A 4
//#define MULTI_B 5
//#define MULTI_C 6
//#define MULTI_D 7

//befor milis -> micros:
//Memtest 32k, noisy - 38 min
//Memtest 32k silent - 4:15 min

//milis -> micros:


#define MULTI_OUT 3
#define MULTI_MASK B00001000

//This will show how long takes to do one loop
// It may be needed to lower FLASH_SIZE while using it.
//#define TIME_TWEAK

#define Z80_DATA_READ     PINB
#define Z80_DATA_WRITE    PORTB
#define Z80_DATA_DIR      DDRB
#define Z80_DATA_DIR_OUT  DDRB = 255;
#define Z80_DATA_DIR_IN   DDRB = 0;

#define Z80_CTRL_READ     PINC
#define Z80_CTRL_WRITE    PORTB
#define Z80_CTRL_DIR      DDRC

#define Z80_MASK_CLK     B00000001
#define Z80_MASK_RESET   B00000010
#define Z80_MASK_WR      B00000100
#define Z80_MASK_RD      B00001000
#define Z80_MASK_MREQ    B00010000
#define Z80_MASK_IRQ     B00100000

#define Z80_MASK_MREQ_RD B00011000

#define MAX_CLK 20000

#define Z80_PIN_CLK     A0

#define Z80_ROM_END     32767

//Serial input buffer size in bytes (not char number). 255 max
#define COMMAND_MAX_LENGHT 32
#define FLASH_SIZE 512
#define SERIAL_BUFFER_SIZE 128

#define HEADER_COUNT 64

#define FLASHDUMP_COLS 32

bool dataReadOnly = 1;
bool clkInternal = 0;

//bool prevClk = 0;
bool oldRead = 0;

bool ctrlClk = 0;
bool ctrlRst = 0;
bool ctrlWr = 0;
bool ctrlRd = 0;
bool ctrlMreq = 0;
bool ctrlIrq = 0;

unsigned long currentAdress = 0;
//unsigned long prevAdress = 0;
byte currentData = 0;

unsigned long tClock = 100000; //1000000/(tClock) = Hz
unsigned long nextTick = 0; 
unsigned long nextHalfTick = 0; 

byte cnt = 0;
//unsigned char memoryFake[COMMAND_MAX_LENGHT];
unsigned char serialFlash[COMMAND_MAX_LENGHT];
//unsigned byte serialFlashCount = 0;
unsigned char flash[FLASH_SIZE];
unsigned char sfCount = 0;
bool written = 0;

//byte debug = 0;
//byte dt;

bool simulation = 0;
bool mute = 0;
bool showMicros = 0;

char serialBuffer[SERIAL_BUFFER_SIZE];
int serialStringLength = 0;

//unsigned long lastTickMicros = 0;

#ifdef TIME_TWEAK
  //for time tweak
  unsigned long time_loopStart, time_loopEnd, time_sum;
  byte timeNo = 0;
  #define TTLENGHT 12
  unsigned long time_table[TTLENGHT];
#endif

void setup() {
  //TODO:
  //avrdude -c usbasp -p m8 -U cal:r:-:h    (values for 1, 2, 4 and 8 MHz)
  //https://www.mexchip.com/en/2018/05/using-atmega8a-oscillator-calibration-byte/
  OSCCAL = 0xaa; // apply calibration value for 8 MHz
  
  Serial.begin(115200);
  Serial.print(F("External clock: "));

  DDRD = DDRD | B11110000;

  flashErase();

  setDataOutput(0);
  readControlPort();
  //prevClk = ctrlClk;

  //doReset();
  delay(1000);

  if(externalClock()){
    setInternalClk(0);
  }else{
    Serial.print(F("not "));
    setInternalClk(1);
  }

  Serial.println(F("available"));

  doReset();
  printHelp();
  printHead();
}

void loop() {
  //Needed for LCD?
  __builtin_avr_delay_cycles (4);

  if(clkInternal){
    while(micros() < nextHalfTick){;}
    
    //TODO: port mnipulation
    digitalWrite(Z80_PIN_CLK, LOW);
    //readSerialInput();  //read Serial only between ticks
    while(Serial.available()){
      //Serial.println();
      char c = Serial.read();
      //Serial.println(c);
      cumulateSerial(c);
      delayMicroseconds(150);
    }

    while(micros() < nextTick){;}

    //TODO: port mnipulation
    digitalWrite(Z80_PIN_CLK, HIGH);
    
    nextTick = micros() + tClock;
    nextHalfTick = nextTick - tClock/2;

  }else{
    //TODO
  }


  //maybe "fullSpeed" variable?

  if(simulation && mute){
    //CTRL Port is read in muteFlash function
    muteFlash();
  }else{
    //TODO: check for faster
    readControlPort();
    
    if(showMicros){
      Serial.print(micros());
      
      if(mute){
        Serial.println();
      }else{
        Serial.print(F(" "));
      }
    }
    noisy();
  }

}

flash

//######### flash ###########
void flashErase(){
  for(int i = 0; i < FLASH_SIZE; i++){
    flash[i] = 0x00;
  }
}

void flashWrite(){
  int bytesNo, checksum;
  int adress = 0;
  unsigned char hn, ln, cmd;

  //Get bytes number
  bytesNo = convChar(serialBuffer[1]) * 16;
  bytesNo += convChar(serialBuffer[2]);

  Serial.print(F("Bytes no: "));
  if(bytesNo < 10){
    Serial.print(F("0"));
  }
  Serial.print(bytesNo);

  if(bytesNo > 32){
    Serial.println(F(". To many bytes - ignore"));
    return;
  }

  //TODO: 
  //Check if bytes number corresponds with accumulated rs

  //Read starting adress
  for(int i = 0; i < 4; i++){
    adress = adress * 16 + convChar(serialBuffer[3+i]);
  }

  Serial.print(F(". Start adress: "));
  Serial.print(adress);
  Serial.print(F("\t:xxXXXXxx"));

  //TODO
  //if adress + bytesNo > flash_SIZE, dont...

  //Data type check
  if(serialBuffer[7] != '0' || serialBuffer[8] != '0'){
    Serial.println(F(" Not data. OK"));
    return;
  }
  
  //Data receive
  for(int i = 0; i < bytesNo; i++){
    hn = convChar(serialBuffer[9+i*2]);
    ln = convChar(serialBuffer[10+i*2]);
    cmd = (hn << 4 ) | ln;
    flash[adress + i] = cmd;
    if(cmd < 16){
      Serial.print(F("0"));
    }
    Serial.print(cmd, HEX);
  }

  Serial.println(F("xx"));
  
  //Ignore checksum
  //TODO?
  
}

void flashDumpHex(){
  byte cs = 0;
  Serial.print(F("\t "));

  for(int i = 0; i < FLASHDUMP_COLS; i++){
    Serial.print(i%10);
    Serial.print(F(" "));
  }

  Serial.print(F("CS"));
  
  for(int i = 0; i < FLASH_SIZE; i++){
    if (i%FLASHDUMP_COLS == 0){
      Serial.println();
      Serial.print(F(":"));
      Serial.print(FLASHDUMP_COLS, HEX);

      if(i < 0x10){
        Serial.print(F("000"));
      }else if(i < 0x100){
        Serial.print(F("00"));
      }else if(i < 0x1000){
        Serial.print(F("0"));
      }
      
      Serial.print(i, HEX);
      Serial.print(F("00"));
      //Serial.print(":\t");
      //Serial.print(":");
      cs = FLASHDUMP_COLS + i + (i>>8);
    }

    if(flash[i] < 0x10){
      Serial.print(F("0"));
    }
    
    Serial.print(flash[i], HEX);

    cs += flash[i];

    if((i+1)%FLASHDUMP_COLS == 0){
      //Serial.print(F(" "));
      if((byte)(256 - cs) < 0x10){
        Serial.print(F("0"));
      }
      Serial.print((byte)(256 - cs), HEX);
    }
    
  }

  Serial.println(F("\n:00000001FF"));
}



void readSerialFlash(){
  //writeToSerialFlash(c, convChar(Serial.read()));

  while(Serial.available() > 1){
    writeToSerialFlash(convChar(Serial.read()), convChar(Serial.read()));
  }
}

void writeToSerialFlash(unsigned char ln, unsigned char hn){
  unsigned char cmd;
  
  if(hn < 16 && ln < 16){
     cmd = (hn << 4 ) | ln;
     serialFlash[sfCount++] = cmd;
//     Serial.print("Got: ");
//     Serial.println(cmd, HEX);
  }
}

void printSerialFlash(){
//  Serial.print(F("Serial flash: "));
  for (int i = 0; i < sfCount; i++){
    Serial.print(serialFlash[i], HEX); 
  }
  //Serial.println();
}

byte serialFlashByte(){
  byte zero;
  zero = serialFlash[0];

  for(int i = 1; i < sfCount; i++){
    serialFlash[i-1] = serialFlash[i];
  }

  sfCount--;
  return zero;
}

serial

//######### serial input ###########
void cumulateSerial(char c){
  //char c = Serial.read();

//  Serial.println();
//  Serial.print(F("Got new sign: "));
  Serial.print(c);
//  Serial.print(F(" 0x"));
//  Serial.println(c, HEX);

  //return;
  //TODO : convChar()

  // On carriage return, process the received data.
  if (c == '\r' || c == '\n' || c == ' ') {
      // Properly terminate the string.
      serialBuffer[serialStringLength] = '\0';
      if(serialStringLength > 0){
        Serial.print(F("serialBuffer: "));
        Serial.println(serialBuffer);
        readSerialInput();
      }
      serialStringLength = 0;
      //Serial.println(F("End of string."));
  }

  // Otherwise buffer the incoming byte.
  else if (c > ' ' && c < 127) {
    if(serialStringLength < SERIAL_BUFFER_SIZE - 1){
      Serial.print(F("Add to string: "));
      Serial.println(c);
      serialBuffer[serialStringLength++] = c;
    }else{
      Serial.println(F("sSL overload!"));
    }
      //Serial.println(F("Cumulate."));
  }
}

inline void readSerialInput(){
  char c = serialBuffer[0];

  if(c == '?'){
    printHelp();
  }
  if(c == 'R'){
    doReset();
  }else if (c == '$'){
    setConfig(serialBuffer[1]);
  /*}else if(c != '\n' && c != '\r'){
    memoryFake[mfCount++] = c;
  }*/
  //TODO serial flash
//  }else if(Serial.available() > 1 && 
//    convChar(c) < 16){
//    readSerialFlash();
//    //printSerialFlash();
//    //Serial.println();
  }else if(c == ':'){
    flashWrite();
  }else if(convChar(c) >= 16){
    Serial.read();
  }else{
    Serial.print(F("Error serial command: "));
    Serial.println(c);
    Serial.read();
  }
}

//void readSerialInput(){
//  while(Serial.available()){
//    char c = Serial.peek();
//    Serial.print(F("Command received: "));
//    Serial.println(c);
//    
//    if(c == ':'){
//      Serial.read();
//      flashWrite();
//    }else{
//      Serial.read();
//    }
//  }
//}

//inline void readSerialInput(){
//  int flines = 0;
//  //delay(2);  //delay to allow byte to arrive in input buffer
//  while (Serial.available()) {
//    delay(2);
//    char c = Serial.peek();
//
//    if(c == '?'){
//      Serial.read();
//      printHelp();
//    }
//    if(c == 'R'){
//      Serial.read();
//      doReset();
//    }else if (c == '$'){
//      Serial.read();
//      setConfig(Serial.read());
//    /*}else if(c != '\n' && c != '\r'){
//      memoryFake[mfCount++] = c;
//    }*/
//    }else if(Serial.available() > 1 && 
//      convChar(c) < 16){
//      readSerialFlash();
//      //printSerialFlash();
//      //Serial.println();
//    }else if(c == ':'){
//      //nextTick = millis() + 200;
//      while(Serial.peek() == ':'){
//        flines++;
//        Serial.read();
//        flashWrite();  
//      }
//      Serial.print(F("Flash lines: "));
//      Serial.println(flines);
//    }else if(convChar(c) >= 16){
//      Serial.read();
//    }else{
//      Serial.print(F("Error serial command: "));
//      Serial.println(c);
//      Serial.read();
//    }
//  }
//}

void setConfig(char mode){
  /*if(mode == 'o' || mode == 'O'){
    dataReadOnly = 1;
  }else*/ 
  if(mode == 'w' || mode == 'W'){
    dataReadOnly = !dataReadOnly;
//  }else if(mode == 'd' || mode == 'D'){
//    debug = !debug;
  }else if(mode == 'r' || mode == 'R'){
    doReset();
  }else if(mode == 's' || mode == 'S'){
    Serial.println(F("TODO"));
    //setClkHz();
  }else if(mode == 'f' || mode == 'F'){
    flashDumpHex();
  }else if(mode == 'e' || mode == 'E'){
    flashErase();
  }else if(mode == 'a' || mode == 'A'){
    //flashErase();
    dataReadOnly = 0;
    simulation = !simulation;
    doReset();
  }else if(mode == 'x' || mode == 'X'){
    simulation = 0;
  }else if(mode == 'u' || mode == 'U'){
    showMicros = !showMicros;
  }else if(mode == 'm' || mode == 'M'){
    mute = !mute;
    Serial.print(F("Mute mode is: "));
    Serial.println(mute);
  }
}

void setClkHz(){
  int readVal = 0;
  int newVal = 0;
  
  while (Serial.available()) {
    delay(2);  //delay to allow byte to arrive in input buffer
    char c = Serial.read();

    if(c >= '0' && c <= '9'){
      readVal = readVal * 10 + c - '0';
    }else{
      break;
    }
  }

  if(readVal <= MAX_CLK && readVal > 0){
    tClock = 1000000/readVal;
    Serial.print(F("New clock value [Hz]: "));
    Serial.println(readVal);
    Serial.print(F("tClock: "));
    Serial.print(tClock);
    Serial.println(F(" uS."));
  }else{
    Serial.println(F("Wrong clock value."));
  }
}

byte convChar(char ch){
  if(ch >= '0' && ch <= '9'){
    return ch - '0';
  }
  
  if(ch >= 'A' && ch <= 'F'){
    return ch - 'A' + 10;
  }

  if(ch >= 'a' && ch <= 'f'){
    return ch - 'a' + 10;
  }
}

//################# Serial info #############

void printHelp(){
  Serial.println(F("\nHelp (?):"));
  Serial.println(F("$r|$R|R - reset Z80"));
  Serial.println(F("$[w|W] - swich write mode"));
  //Serial.println(F("$[d|D] - swich debug mode"));
  //Serial.println(F("$[t|T] - swich internal/external clock"));
  Serial.print(F("$[s|S]{val} - set clck to val in Hz (1 to MAX_CLKHz)"));
    Serial.println(MAX_CLK);
  Serial.println(F("$[f|F] - dump FLASH in HEX"));
  Serial.println(F("$[e|E] - erase flash"));
  Serial.println(F("$[a|A] - start simulation"));
  Serial.println(F("$[x|X] - stop simulation"));
  Serial.println(F("$[m|M] - mute mode"));
  Serial.println(F("$[u|U] - show/hide micros"));
  Serial.println(F(": ... - put Intel HEX into flash memory"));
  Serial.println();
}

void printHead(){
  //Serial.println(F("RO Sim | Clk Rst Wr Rd MRq IRq| Adress\t| Comment\t\t\t\t| BIN\t\tHEX\tDEC"));
  //Serial.print(F("RO Sim | Wr Rd MRq IRq | Adress\t| Comment\t\t\t\t| BIN\t    HEX ASCII"));
  Serial.print(F("RO Sim | Adress\t| Comment\t\t| BIN\t    HEX ASCII"));
  if(sfCount){
    Serial.print(F("\t| SerialFlash"));
  }
  Serial.println();
}

void printInfo(){
  Serial.print(F(" "));
  Serial.print(dataReadOnly);
  Serial.print(F("  "));
  Serial.print(simulation);
  Serial.print(F("  |  "));
//  Serial.print(ctrlClk);
//  Serial.print(F("   "));
//  Serial.print(ctrlRst);
//  Serial.print(F("  "));
/*  Serial.print(ctrlWr);
  Serial.print(F("  "));
  Serial.print(ctrlRd);
  Serial.print(F("   "));
  Serial.print(ctrlMreq);
  Serial.print(F("   "));
  Serial.print(ctrlIrq);  
  Serial.print(F(" | "));*/
  Serial.print(currentAdress, HEX);
  Serial.print(F("\t| "));
}

void printData(){
  Serial.print(F("\t| B"));
  for(int i = 7; i >= 0; i--){
    Serial.print(bitRead(currentData,i));
  }
  Serial.print(F(" 0x"));
  //Serial.print(currentData, HEX);
  if (currentData<0x10) {
    Serial.print(F("0"));
  } 
  Serial.print(currentData, HEX);
  Serial.print(F("    "));

  Serial.print((char)currentData);
}

simulate

//######### simulate ###########
inline void muteFlash(){

  if(Z80_CTRL_READ&Z80_MASK_MREQ_RD){
    //NOT read from any memory
    
    Z80_DATA_DIR_IN
    Z80_DATA_WRITE = 0;
  }else{
    //MREQ = 0 AND RD = 0 -> read from memory
    
    //read current adress
    readSilentSimulationAdress();
          
    if(currentAdress < FLASH_SIZE){
      //put current flash byte to DATA port
      Z80_DATA_DIR_OUT
      Z80_DATA_WRITE = flash[currentAdress];
    }else if(currentAdress <= Z80_ROM_END){
      //if adress does not lay between flash and ram, exit simulation
      simulationOff();
      Z80_DATA_DIR_OUT
      Z80_DATA_WRITE = 0;
    }
  }
}

void noisy(){
  //read current adress
  readAdress();

  //Print header info from time to time
  if(cnt++ == HEADER_COUNT){
    printHead();
    cnt = 0;
  }

  if(ctrlMreq == 0 && ctrlRd == 0 && ctrlIrq == 1 && ctrlWr == 1){
    if(written == 0){   
      //if it is new read cycle
      printInfo();    
      Serial.print(F("Z80 <- MEM ("));

      if(currentAdress > Z80_ROM_END){
        //we are outside of ROM, probably in RAM
        readData();
        Serial.print(F("RAM)"));
      }else if(dataReadOnly == 0){

        if(simulation == 1){
          currentData = flash[currentAdress];
          Serial.print(F("Sim.)"));
        }else if(sfCount){
          currentData = serialFlashByte();    
          Serial.print(F("Serial)"));
        }else{
          currentData = 0;
          Serial.print(F("NOP)"));
        }
        
        Z80_DATA_DIR_OUT
        Z80_DATA_WRITE = currentData;

      }else{
        //Serial.print(" | Read-only mode: ");
        if(sfCount > 0){
          currentData = serialFlashByte();
        }else{
          currentData = 0;
        }

        Serial.print(F("R/O)"));
      }

      printData();
      if(sfCount){
        Serial.print(F("\t| "));
        printSerialFlash();
      }
      Serial.println();
      
      written = 1;
    }
  }else{
    Z80_DATA_DIR_IN
    Z80_DATA_WRITE = 0;
  }

  if(ctrlMreq == 1 && ctrlRd == 1 && ctrlIrq == 1 && ctrlWr == 1){
    oldRead = 0;
    written = 0;
  }
  
  if(oldRead == 0){
    if(ctrlMreq == 0 && ctrlRd == 1 && ctrlIrq == 1 && ctrlWr == 0){
      //Z80 writes to memory
        printInfo();
        Serial.print(F("Z80 -> MEM"));
        
        if(currentAdress > Z80_ROM_END){
          //we are outside of ROM, probably in RAM
          Serial.print(F(" (RAM)"));
        }else{
          Serial.print(F("\t"));
        }
        
        readData();
        printData();
        Serial.println();
        oldRead = 1;
        
    }else if(ctrlMreq == 1 && ctrlRd == 0 && ctrlIrq == 0 && ctrlWr == 1){
        printInfo();
        Serial.print(F("Z80 <- IO\t"));
        readData();
        printData();
        Serial.println();
        oldRead = 1;
      
    }else if(ctrlMreq == 1 && ctrlRd == 1 && ctrlIrq == 0 && ctrlWr == 0){
        printInfo();
        Serial.print(F("Z80 -> IO\t"));
        readData();
        printData();
        Serial.println();
        oldRead = 1;
      
    }
  }
}

inline void checkSimulationAdress(){
  if(
      simulation
      && currentAdress > FLASH_SIZE
      && currentAdress <= Z80_ROM_END 
      && ctrlRd == 0
      && ctrlMreq == 0
      ){
    simulationOff();
  }
}

void simulationOff(){
  simulation = 0;
  Serial.println();
  Serial.print(currentAdress);
  Serial.println(F(": Simulation off"));
}

z80



//######### z80 read ###########
void readControlPort(){
  byte ctrl;
  ctrl = Z80_CTRL_READ;

  ctrlClk = ctrl & Z80_MASK_CLK;
  ctrlRst = ctrl & Z80_MASK_RESET;
  ctrlWr = ctrl & Z80_MASK_WR;
  ctrlRd = ctrl & Z80_MASK_RD;
  ctrlMreq = ctrl & Z80_MASK_MREQ;
  ctrlIrq = ctrl & Z80_MASK_IRQ;  
}

void readAdress(){
  //MULTI OUT 3
  currentAdress = 0;
  
  for(int i = 15; i>=0; i--){
    setMultiplexer(i);
    
    currentAdress = currentAdress << 1;

    if(PIND&MULTI_MASK){
      currentAdress++;
    }
  }

  checkSimulationAdress();
}

inline void readSilentSimulationAdress(){
  //MULTI OUT 3
  currentAdress = 0;
  
//  for(char i = 15; i>=0; i--){
//    //setMultiplexer(i);
//    PORTD = i << 4;
//    
//    currentAdress = currentAdress << 1;
//
//    if(PIND&MULTI_MASK){
//      currentAdress++;
//    }
//  }

  PORTD = B11110000;  //15
  currentAdress = currentAdress << 1;
  if(PIND&MULTI_MASK){currentAdress++;}
  PORTD = B11100000;  //14
  currentAdress = currentAdress << 1;
  if(PIND&MULTI_MASK){currentAdress++;}
  PORTD = B11010000;  //13
  currentAdress = currentAdress << 1;
  if(PIND&MULTI_MASK){currentAdress++;}
  PORTD = B11000000;  //12
  currentAdress = currentAdress << 1;
  if(PIND&MULTI_MASK){currentAdress++;}
  PORTD = B10110000;  //11
  currentAdress = currentAdress << 1;
  if(PIND&MULTI_MASK){currentAdress++;}
  PORTD = B10100000;  //10
  currentAdress = currentAdress << 1;
  if(PIND&MULTI_MASK){currentAdress++;}
  PORTD = B10010000;  //09
  currentAdress = currentAdress << 1;
  if(PIND&MULTI_MASK){currentAdress++;}
  PORTD = B10000000;  //08
  currentAdress = currentAdress << 1;
  if(PIND&MULTI_MASK){currentAdress++;}
  PORTD = B01110000;  //07
  currentAdress = currentAdress << 1;
  if(PIND&MULTI_MASK){currentAdress++;}
  PORTD = B01100000;  //06
  currentAdress = currentAdress << 1;
  if(PIND&MULTI_MASK){currentAdress++;}
  PORTD = B01010000;  //05
  currentAdress = currentAdress << 1;
  if(PIND&MULTI_MASK){currentAdress++;}
  PORTD = B01000000;  //04
  currentAdress = currentAdress << 1;
  if(PIND&MULTI_MASK){currentAdress++;}
  PORTD = B00110000;  //03
  currentAdress = currentAdress << 1;
  if(PIND&MULTI_MASK){currentAdress++;}
  PORTD = B00100000;  //02
  currentAdress = currentAdress << 1;
  if(PIND&MULTI_MASK){currentAdress++;}
  PORTD = B00010000;  //01
  currentAdress = currentAdress << 1;
  if(PIND&MULTI_MASK){currentAdress++;}
  PORTD = B00000000;  //00
  currentAdress = currentAdress << 1;
  if(PIND&MULTI_MASK){currentAdress++;}

//  if(currentAdress > FLASH_SIZE){
//    simulation = 0;
//    Serial.println();
//    Serial.print(currentAdress);
//    Serial.println(F(": Simulation off"));
//  }

}

inline void readData(){
  currentData = Z80_DATA_READ;
}

//######### z80 drive/set ###########

void doReset(){

  //TODO: check if there is a clock source on!
  
  Serial.print(F("Reset"));

  setReset(0);

  if(clkInternal){
    for(int i = 0; i < 7; i++){
      digitalWrite(Z80_PIN_CLK, !digitalRead(Z80_PIN_CLK));
      delay(10);
    }
  }else{
    byte clkCnt=0;
    bool clkLastState=0;
    bool clk = 0;
  
    //wait for clk LOW
    while(Z80_CTRL_READ & Z80_MASK_CLK){;}
  
    while(clkCnt < 7){
      clk = Z80_CTRL_READ & Z80_MASK_CLK;
      //Serial.print(clk);
      if(clkLastState != clk){
        clkCnt++;
        clkLastState = clk;
        //Serial.println("...");
      }
    }
  }

  setReset(1);
  Serial.println(F("."));
}

//Check if there is external clock source
bool externalClock(){
  unsigned long stopTime = millis() + 2000;
  bool on=0;
  //TODO: convert to port manipulation?
  pinMode(Z80_PIN_CLK , INPUT_PULLUP);
  
  while(millis() < stopTime){
    if((Z80_CTRL_READ & Z80_MASK_CLK) == 0){
      //if something pulls down clk down then there is 
      // external clock source.
      on = 1;
      break;
    }
  }

  return on;
}

//enable A8 internal clock
void setInternalClk(bool setClk){
  if(setClk){
    clkInternal = 1;
    //TODO: convert to port manipulation?
    pinMode(Z80_PIN_CLK, OUTPUT);
    digitalWrite(Z80_PIN_CLK, LOW);
    nextTick = millis() + tClock;
    
  }else{
    clkInternal = 0;
    //TODO: convert to port manipulation?
    pinMode(Z80_PIN_CLK, INPUT);
  }
}

void setMultiplexer(int val){
      //PORTD = PORTD | (B11110000 & (val << 4));
      PORTD = val << 4;
  //}
}

void setReset(bool r){
  //TODO: convert to Port Manipulation  
  if(r){
    pinMode(15, INPUT_PULLUP);
  }else{
    pinMode(15, OUTPUT);
    digitalWrite(15, LOW);
  }
}

void setDataOutput(bool en){
  if(en && !dataReadOnly){
    DDRB = B11111111; // sets Arduino pins 8 to 15 as outputs
  }else{
    DDRB = B00000000; // sets as inputs 
  }
}

So speeding up cumulateSerial()?
Currently rest of the loop is SLOW (10Hz i suppose), I'll put cumulateSerial in while(micros() < nextHalfTick){;} and check it.

Ok, that helped I think.

I've modified my loop to:

void loop() {
  //Needed for LCD?
  __builtin_avr_delay_cycles (4);

  if(clkInternal){
    while(micros() < nextHalfTick){
        while(Serial.available()){
            char c = Serial.read();
            cumulateSerial(c);
        }
    }
    
    //TODO: port mnipulation
    digitalWrite(Z80_PIN_CLK, LOW);
    //readSerialInput();  //read Serial only between ticks
//    while(Serial.available()){
//      //Serial.println();
//      char c = Serial.read();
//      //Serial.println(c);
//      cumulateSerial(c);
//      //delayMicroseconds(150);
//    }

    while(micros() < nextTick){
      while(Serial.available()){
        char c = Serial.read();
        cumulateSerial(c);
      }
    }

    //TODO: port mnipulation
    digitalWrite(Z80_PIN_CLK, HIGH);
    
    nextTick = micros() + tClock;
    nextHalfTick = nextTick - tClock/2;

  }else{
    //TODO
  }


  //maybe "fullSpeed" variable?

  if(simulation && mute){
    //CTRL Port is read in muteFlash function
    muteFlash();
  }else{
    //TODO: check for faster
    readControlPort();
    
    if(showMicros){
      Serial.print(micros());
      
      if(mute){
        Serial.println();
      }else{
        Serial.print(F(" "));
      }
    }
    noisy();
  }

}

But currently my response is:

:Add to string: :
2Add to string: 2
0Add to string: 0
0Add to string: 0
0Add to string: 0
0Add to string: 0
0Add to string: 0
0Add to string: 0
0Add to string: 0
9Add to string: 9
9Add to string: 9
0Add to string: 0
0Add to string: 0
1Add to string: 1
1Add to string: 1
2Add to string: 2
2Add to string: 2
3Add to string: 3
3Add to string: 3
4Add to string: 4
4Add to string: 4
5Add to string: 5
5Add to string: 5
6Add to string: 6
6Add to string: 6
7Add to string: 7
7Add to string: 7
8Add to string: 8
8Add to string: 8
AAdd to string: A
AAdd to string: A
BAdd to string: B
BAdd to string: B
CAdd to string: C
CAdd to string: C
DAdd to string: D
DAdd to string: D
EAdd to string: E
EAdd to string: E
FAdd to string: F
FAdd to string: F
9Add to string: 9
9Add to string: 9
0Add to string: 0
0Add to string: 0
1Add to string: 1
1Add to string: 1
2Add to string: 2
2Add to string: 2
3Add to string: 3
3Add to string: 3
4Add to string: 4
4Add to string: 4
5Add to string: 5
5Add to string: 5
6Add to string: 6
6Add to string: 6
7Add to string: 7
7Add to string: 7
8Add to string: 8
8Add to string: 8
AAdd to string: A
AAdd to string: A
BAdd to string: B
BAdd to string: B
CAdd to string: C
CAdd to string: C
DAdd to string: D
DAdd to string: D
EAdd to string: E
EAdd to string: E

So it is still too short: 4 signs + newline has been dropped.
Even on mute() with simulation on.

Atmega runs on internal (calibrated) clock of 8 MHz.

Thanks anyway. Still looking for solution.

If you're trying to simulate a Z80 at full speed, I don't think that an 8MHz processor can cut it. Get a Teensy or similar.

I suggest that every time around loop you need to read whatever is there in the serial buffer. Waiting for ticks is overflowing the buffer still.

A true Z80 should be fully static - you should be able to run it at any speed.

I'm sorry, I do not understand...
Do You suggest to write function that reads everything until eg. '\n'? It seems to be a good solution for me! Or do You have something else in mind?

============== OT ===============

Oh no, I'm not hoping to run it at full speed! My previous versions worked at speed around 350 Hz, that's why I've started to rewrite my code. Currently I measure about 15kHz (with logic analyzer) and that's far more than enough for testing purposes. But by programming atmega to be even faster is quite cool way for me to learn some things also.
edit. And, knowing I won'g get anything impressive with atmega, I even build UART sending module that can be driven by CPU@10Hz. I'm quite prod of it, to be honest :wink:

That's just half true. There were two basic versions of Z80: n-MOS and c-MOS. First one was NOT fully static (and thats one I'm currently have in my computer, c-MOS version I own is too expensive to do tests on it ;)) and by my observations, I can tell that frequencies below 10-20 Hz causes registers to loose data.

Do you have to run at 115200? That gives you about 5 milliseconds before the buffer overflows.

However you do it, you need to service serial quite promptly or data will be lost.

No, I did run at 115k2 because there is quite lot data transfered from atmega to PC, but then mute came to my mind. Also I was afraid of calibration thing and it was only speed for serial to work. Now I know it is SOOOOO easy!

Ok, lets say that at full speed I can get 10kHz. This gives 10 µs for one round of mute() function. That's where overflow comes...

I reduced baud to 9600 (will calculate/test higher rates someday) and it works just fine now.
Thank You wildbill and AWOL.

Here's my final (yeah, right...) version of cumulate function:

void cumulateSerial(){
  while(1){
    if(Serial.available()){
      char c = Serial.read();
    
      //TODO : convChar()
    
      // On carriage return, process the received data.
      if (c == '\r' || c == '\n' || c == ' ') {
          // Properly terminate the string.
          serialBuffer[serialStringLength] = '\0';
          if(serialStringLength > 0){
            Serial.print(F("serialBuffer: "));
            Serial.println(serialBuffer);
            readSerialInput();
          }
          serialStringLength = 0;
          break;
          //Serial.println(F("End of string."));
      }
    
      // Otherwise buffer the incoming byte.
      else if (c > ' ' && c < 127) {
        if(serialStringLength < SERIAL_BUFFER_SIZE - 1){
          /*
           * NO TIME TO PRINT ANYTHING HERE!
           * Serial.print(F("Add to string: "));
           * Serial.println(c);
           */
          serialBuffer[serialStringLength++] = c;
        }else{
          Serial.println(F("sSL overload!"));
        }
          //Serial.println(F("Cumulate."));
      }
    }
  }
}

Best regards!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.