Ejemplo n.º 1
0
int16_t
parse_cmd_adc_get(char *cmd, char *output, uint16_t len)
{
  uint16_t adc;
  uint8_t channel;
  uint8_t ret = 0;
  if (cmd[0] && cmd[1])
  {
    channel = cmd[1] - '0';
    if (channel < ADC_CHANNELS)
    {
      adc = adc_get(channel);
      channel = ADC_CHANNELS;
      goto adc_out;
    }
    else
      return ECMD_ERR_PARSE_ERROR;
  }
  for (channel = 0; channel < ADC_CHANNELS; channel++)
  {
    adc = adc_get(channel);
  adc_out:
    output[0] = NIBBLE_TO_HEX(LO4(HI8(adc)));
    output[1] = NIBBLE_TO_HEX(HI4(LO8(adc)));
    output[2] = NIBBLE_TO_HEX(LO4(adc));
    output[3] = ' ';
    output[4] = 0;
    ret += 4;
    output += 4;
  }
  return ECMD_FINAL(ret);
}
Ejemplo n.º 2
0
void do_if_stage()
{
    byte_t instr = HPACK(I_NOP, F_NONE);
    byte_t regids = HPACK(REG_NONE, REG_NONE);
    word_t valc = 0;
    word_t valp = f_pc = gen_f_pc();

    /* Ready to fetch instruction.  Speculatively fetch register byte
       and immediate word
       */
    imem_error = !get_byte_val(mem, valp+START_PLACE, &instr);
    imem_icode = HI4(instr);
    imem_ifun = LO4(instr);
    if (!imem_error) {
        byte_t junk;
        /* Make sure can read maximum length instruction */
        imem_error = !get_byte_val(mem, valp+5 + START_PLACE, &junk);
    }
    if_id_next->icode = gen_f_icode();
    if_id_next->ifun  = gen_f_ifun();
    if (!imem_error) {
        sim_log("\tFetch: f_pc = 0x%x, imem_instr = %s, f_instr = %s\n",
                f_pc, iname(instr),
                iname(HPACK(if_id_next->icode, if_id_next->ifun)));
    }

    instr_valid = gen_instr_valid();
    if (!instr_valid) 
        sim_log("\tFetch: Instruction code 0x%x invalid\n", instr);
    if_id_next->status = gen_f_stat();

    valp++;
    if (gen_need_regids()) {
        get_byte_val(mem, valp + START_PLACE, &regids);
        valp ++;
    }
    if_id_next->ra = HI4(regids);
    if_id_next->rb = LO4(regids);
    if (gen_need_valC()) {
        get_word_val(mem, valp + START_PLACE, &valc);
        valp+= 4;
    }
    if_id_next->valp = valp;
    if_id_next->valc = valc;
    /*
    if(gen_need_regids() && if_id_next->valc)
        printf("##### vap: %d %d %d\n", if_id_next->ra, if_id_next->rb, if_id_next->valc);
        */

    pc_next->pc = gen_f_predPC();

    pc_next->status = (if_id_next->status == STAT_AOK) ? STAT_AOK : STAT_BUB;

    if_id_next->stage_pc = f_pc;
}
Ejemplo n.º 3
0
void output_byte(uint8_t rs, uint8_t data, uint8_t en)
{
    output_nibble(rs, HI4(data), en);
    output_nibble(rs, LO4(data), en);

#ifdef HD44780_READBACK
    /* wait until command is executed by checking busy flag, with timeout */

    /* max execution time is for return home command,
     * which takes at most 1.52ms = 1520us */
    uint8_t busy, timeout = 200;
    do {
        busy = input_byte(0,en) & _BV(BUSY_FLAG);
        _delay_us(10);
        timeout--;
    } while (busy && timeout > 0);
    #ifdef DEBUG
    if (timeout == 0)
        debug_printf("lcd timeout!\n");
    #endif
#else
    /* just wait the maximal time a command can take... */
    _delay_ms(2);
#endif
}
Ejemplo n.º 4
0
uint8_t byte2hex (uint8_t value, char *string)
{
  // convert high nibble into hex ascii
  string[0] = NIBBLE_TO_HEX(HI4(value));

  // convert low nibble into hex ascii
  string[1] = NIBBLE_TO_HEX(LO4(value));

  return (2);
}
Ejemplo n.º 5
0
// Look up or generate waveform for ProTracker vibrato/tremolo oscillator
static int8_t do_osc(pto_t *p_osc) {
  int8_t sample = 0;
  int16_t mul;
  switch (p_osc->mode & 0x03) {
    case 0: // Sine
      sample = pgm_read_byte(&sine_tbl[(p_osc->offset) & 0x1F]);
      if (p_osc->offset & 0x20) sample = -sample;
      break;
    case 1: // Saw
      sample = -(p_osc->offset << 2);
      break;
    case 2: // Square
      sample = (p_osc->offset & 0x20) ? 127 : -128;
      break;
    case 3: // Noise (random)
      sample = rand();
      break;
  }
  mul = sample * LO4(p_osc->fxp);
  p_osc->offset = (p_osc->offset + HI4(p_osc->fxp));
  return mul >> 6;
}
Ejemplo n.º 6
0
// Look up or generate waveform for ProTracker vibrato/tremolo oscillator
static int8_t do_osc( osc_t *p_osc ) {
  int8_t sample = 0;
  int16_t mul;

  switch( p_osc->mode & 0x03 ) {
    case 0: // Sine
      sample = ROM_READB( &sine[ ( p_osc->offset ) & 0x3F ] );
      if( sample > 127 ) sample -= 256;
      break;
    case 1: // Square
      sample = ( p_osc->offset & 0x20 ) ? 127 : -128;
      break;
    case 2: // Saw
      sample = ( ( p_osc->offset << 2 ) & 0xFF ) - 128;
      break;
    case 3: // Noise (random)
      sample = rand() & 0xFF;
      break;
  }
  mul = sample * LO4( p_osc->fxp );
  p_osc->offset = ( p_osc->offset + HI4( p_osc->fxp ) - 1 ) & 0xFF;
  return mul / 64;
}
Ejemplo n.º 7
0
char *amqp_util_encode(char *key, char *dest) {
	char *p, *end;
 	if ((strlen(key) == 1) && (key[0] == '#' || key[0] == '*')) {
 		*dest++ = key[0];
		*dest = '\0';
		return dest;
    }
	for (p = key, end = key + strlen(key); p < end; p++) {
		if (KEY_SAFE(*p)) {
			*dest++ = *p;
		} else if (*p == '.') {
			memcpy(dest, "%2E", 3);
			dest += 3;
		} else if (*p == ' ') {
			*dest++ = '+';
		} else {
			*dest++ = '%';
			sprintf(dest, "%c%c", hexint(HI4(*p)), hexint(LO4(*p)));
			dest += 2;
		}
	}
	*dest = '\0';
	return dest;
}
Ejemplo n.º 8
0
// Progress module by one tick
static void play_module() {
  uint8_t  ch, fx, fxp;
  uint8_t  temp_b;
  uint16_t temp_w;
  fxm_t   *p_fxm;
  dma_t   *p_dma;
  bool     pattern_jump = false;
  uint8_t  ix_period;
  uint8_t  ix_sample;
  uint8_t *p_ptn;

  // Advance tick
  if( ++tick == speed ) tick = 0;

  // Handle row delay
  if( delay ) {
    if( tick == 0 ) delay--;
    return;
  }

  // Advance playback
  if( tick == 0 ) {
    if( ++ix_row == 64 ) {
      ix_row = 0;
      if( ++ix_order == ROM_READB( &p_mod->order_count ) ) ix_order = 0;
    }
    // Forced order/row
    if( ix_nextorder != 0xFF ) {
      ix_order = ix_nextorder;
      ix_nextorder = 0xFF;
    }
    if( ix_nextrow != 0xFF ) {
      ix_row = ix_nextrow;
      ix_nextrow = 0xFF;
    }

  }

  // Set up pointers
  p_ptn = ( ( uint8_t* )p_mod )
        + sizeof( ptm_t )
        + ( ROM_READB( &p_mod->order[ ix_order ] ) << 10 )
        + ( ix_row << 4 );

  p_fxm = fxm;
  p_dma = dma;

  for( ch = 0; ch != 4; ch++ ) {

    // Deconstruct cell (what the hell were they smoking?)
    temp_b     = ROM_READB( p_ptn++ );                // sample.msb and period.msb
    temp_w     = ( temp_b & 0x0F ) << 8;
    ix_sample  = temp_b & 0xF0;
    temp_w    |= ROM_READB( p_ptn++ );                // period.lsb
    temp_b     = ROM_READB( p_ptn++ );                // sample.lsb and effect
    ix_sample |= HI4( temp_b );
    fx         = LO4( temp_b ) << 4;
    fxp        = ROM_READB( p_ptn++ );                // parameters
    if( fx == 0xE0 ) {
      fx |= HI4( fxp );                   // extended parameters
      fxp  &= 0x0F;
    }
    ix_period = 0x7F;                     // period index
    if( temp_w ) {
      for( temp_b = 0; temp_b != 36; temp_b++ ) {
        if( ROM_READW( &period_tbl[ 0 ][ temp_b ] ) == temp_w ) {
          ix_period = temp_b;
          break;
        }
      }
    }

    // General effect parameter memory
    // NOTE: Unsure if this is true to the original ProTracker, but alot of
    //       modern players and trackers do implement this functionality.
    if( fx == 0x10 || fx == 0x20 || fx == 0xE1 || fx == 0xE2 || fx == 0x50 || fx == 0x60 || fx == 0xA0 ) {
      if( fxp ) {
        p_fxm->param = fxp;
      } else {
        fxp = p_fxm->param;
      }
    }

    if( tick == ( fx == 0xED ? fxp : 0 ) ) {
      if( ix_sample != 0 ) {
        // Cell has sample
        temp_b = ix_sample - 1;
        p_fxm->sample = temp_b;
        p_fxm->volume = sample[ temp_b ].volume;
        // Reset volume
        p_dma->volume = sample[ temp_b ].volume;
      }

      // Set tuning
      if( fx == 0xE5 ) sample[ p_fxm->sample ].tuning = fxp;
      // Reset oscillators
      if( ( p_fxm->vibr.mode & 0x4 ) == 0x0 ) p_fxm->vibr.offset = 0;
      if( ( p_fxm->trem.mode & 0x4 ) == 0x0 ) p_fxm->trem.offset = 0;

      if( ix_period != 0x7F ) {
        // Cell has note
        if( fx == 0x30 || fx == 0x50 ) {
          // Tone-portamento effect setup
          p_fxm->port_target = ROM_READW( &period_tbl[ sample[ ix_sample ].tuning ][ ix_period ] );
        } else {
          // Start note
          temp_b = p_fxm->sample;
          note_start( p_dma, temp_b, ix_period, ( fx == 0x90 ? fxp : 0 ) );
          // Set required effect memory parameters
          p_fxm->period = ROM_READW( &period_tbl[ sample[ temp_b ].tuning ][ ix_period ] );
        }
      }

      // Effects processed when tick = 0
      switch( fx ) {
        case 0x30: // Portamento
          if( fxp ) p_fxm->port_speed = fxp;
          break;
        case 0xB0: // Jump to pattern
          ix_nextorder = ( fxp >= ROM_READB( &p_mod->order_count ) ? 0x00 : fxp );
          ix_nextrow = 0;
          pattern_jump = true;
          break;
        case 0xC0: // Set volume
          p_fxm->volume = MIN( fxp, 0x40 );
          p_dma->volume = p_fxm->volume;
          break;
        case 0xD0: // Jump to row
          fxp = HI4( fxp ) * 10 + LO4( fxp );
          if( !pattern_jump ) ix_nextorder = ( ( ix_order + 1 ) >= ROM_READB( &p_mod->order_count ) ? 0x00 : ix_order + 1 );
          pattern_jump = true;
          ix_nextrow = ( fxp > 63 ? 0 : fxp );
          break;
        case 0xF0: // Set speed
          if( fxp > 0x20 ) {
            cia = SAMPLE_RATE / ( ( 24 * fxp ) / 60 );
          } else {
            speed = fxp;
          }
          break;
        case 0x40: // Vibrato
          if( fxp ) p_fxm->vibr.fxp = fxp;
          break;
        case 0x70: // Tremolo
          if( fxp ) p_fxm->trem.fxp = fxp;
          break;
        case 0xE1: // Fine slide up
          p_fxm->period = MAX( p_fxm->period - fxp, PERIOD_MIN );
          p_dma->rate = SYS_FREQ / p_fxm->period;
          break;
        case 0xE2: // Fine slide down
          p_fxm->period = MIN( p_fxm->period + fxp, PERIOD_MAX );
          p_dma->rate = SYS_FREQ / p_fxm->period;
          break;
        case 0xE3: // Glissando control
          p_fxm->glissando = ( fxp != 0 );
          break;
        case 0xE4: // Set vibrato waveform
          p_fxm->vibr.mode = fxp;
          break;
        case 0xE6: // Loop-back (advanced looping)
          if( fxp == 0x0 ) {
            p_fxm->loop_order = ix_order;
            p_fxm->loop_row   = ix_row;
          } else {
            p_fxm->loop_count = ( p_fxm->loop_count ? p_fxm->loop_count - 1 : fxp );
            if( p_fxm->loop_count ) {
              ix_nextorder = p_fxm->loop_order;
              ix_nextrow   = p_fxm->loop_row;
            }
          }
          break;
        case 0xE7: // Set tremolo waveform
          p_fxm->trem.mode = fxp;
          break;
        case 0xEA: // Fine volume slide up
          p_fxm->volume = MIN( p_fxm->volume + fxp, 0x40 );
          p_dma->volume = p_fxm->volume;
          break;
        case 0xEB: // Fine volume slide down
          p_fxm->volume = MAX( p_fxm->volume - fxp, 0 );
          p_dma->volume = p_fxm->volume;
          break;
        case 0xEE: // Delay
          delay = fxp;
          break;
      }

    } else {
      // Effects processed when tick > 0
      switch( fx ) {
        case 0x10: // Slide up
          p_fxm->period = MAX( p_fxm->period - fxp, PERIOD_MIN );
          p_dma->rate = SYS_FREQ / p_fxm->period;
          break;
        case 0x20: // Slide down
          p_fxm->period = MIN( p_fxm->period + fxp, PERIOD_MAX );
          p_dma->rate = SYS_FREQ / p_fxm->period;
          break;
        case 0xE9: // Retrigger note
          temp_b = tick; while( temp_b >= fxp ) temp_b -= fxp;
          if( temp_b == 0 ) note_start( p_dma, p_fxm->sample, ix_period, ( fx == 0x90 ? fxp : 0 ) );
          break;
        case 0xEC: // Note cut
          if( fxp == tick ) p_dma->volume = 0x00;
          break;
        default:   // Multi-effect processing
          // Portamento
          if( fx == 0x30 || fx == 0x50 ) {
            if( p_fxm->period < p_fxm->port_target ) p_fxm->period = MIN( p_fxm->period + p_fxm->port_speed,  p_fxm->port_target );
            else                                     p_fxm->period = MAX( p_fxm->period - p_fxm->port_speed,  p_fxm->port_target );
            if( p_fxm->glissando ) p_dma->rate = SYS_FREQ / glissando( ch );
            else                   p_dma->rate = SYS_FREQ / p_fxm->period;
          }
          // Volume slide
          if( fx == 0x50 || fx == 0x60 || fx == 0xA0 ) {
            if( ( fxp & 0xF0 ) == 0 ) p_fxm->volume -= ( LO4( fxp ) );
            if( ( fxp & 0x0F ) == 0 ) p_fxm->volume += ( HI4( fxp ) );
            p_fxm->volume = MAX( MIN( p_fxm->volume, 0x40 ), 0 );
            p_dma->volume = p_fxm->volume;
          }
      }
    }

    // Normal play and arpeggio
    if( fx == 0x00 ) {
      temp_b = tick; while( temp_b > 2 ) temp_b -= 2;
      if( temp_b == 0 ) {
        // Reset
        p_dma->rate = SYS_FREQ / p_fxm->period;
      } else if( fxp ) {
        // Arpeggio
        p_dma->rate = SYS_FREQ / arpeggio( ch, ( temp_b == 1 ? HI4( fxp ) : LO4( fxp ) ) );
      }
    } else if( fx == 0x40 || fx == 0x60 ) {
      // Vibrato
      p_dma->rate = SYS_FREQ / ( p_fxm->period + do_osc( &p_fxm->vibr ) );
    } else if( fx == 0x70 ) {
      // Tremolo
      temp_b = p_fxm->volume + do_osc( &p_fxm->trem );
      p_dma->volume = MAX( MIN( temp_b, 0x40 ), 0 );
    }

    p_fxm++;
    p_dma++;
  }
}
Ejemplo n.º 9
0
/* Execute single instruction.  Return exception condition. */
exc_t step_state(state_ptr s, FILE *error_file)
{
    word_t argA, argB;
    byte_t byte0 = 0;
    byte_t byte1 = 0;
    itype_t hi0;
    alu_t  lo0;
    reg_id_t hi1 = REG_NONE;
    reg_id_t lo1 = REG_NONE;
    bool_t ok1 = TRUE;
    word_t cval;
    word_t okc = TRUE;
    word_t val, dval;
    bool_t need_regids;
    bool_t need_imm;

    word_t ftpc = s->pc;

    if (!get_byte_val(s->m, ftpc, &byte0)) {
	if (error_file)
	    fprintf(error_file,
		    "PC = 0x%x, Invalid instruction address\n", s->pc);
	return EXC_ADDR;
    }
    ftpc++;

    hi0 = HI4(byte0);
    lo0 = LO4(byte0);

    need_regids =
	(hi0 == I_RRMOVL || hi0 == I_ALU || hi0 == I_PUSHL ||
	 hi0 == I_POPL || hi0 == I_IRMOVL || hi0 == I_RMMOVL ||
	 hi0 == I_MRMOVL || hi0 == I_ALUI);

    if (need_regids) {
	ok1 = get_byte_val(s->m, ftpc, &byte1);
	ftpc++;
	hi1 = HI4(byte1);
	lo1 = LO4(byte1);
    }

    need_imm =
	(hi0 == I_IRMOVL || hi0 == I_RMMOVL || hi0 == I_MRMOVL ||
	 hi0 == I_JXX || hi0 == I_CALL || hi0 == I_ALUI);

    if (need_imm) {
	okc = get_word_val(s->m, ftpc, &cval);
	ftpc += 4;
    }

    switch (hi0) {
    case I_NOP:
	s->pc = ftpc;
	break;
    case I_HALT:
	s->pc = ftpc;
	return EXC_HALT;
	break;
    case I_RRMOVL:
	if (!ok1) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address\n", s->pc);
	    return EXC_ADDR;
	}
	if (hi1 >= 8) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid register ID 0x%.1x\n",
			s->pc, hi1);
	    return EXC_INSTR;
	}
	if (lo1 >= 8) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid register ID 0x%.1x\n",
			s->pc, lo1);
	    return EXC_INSTR;
	}
	val = get_reg_val(s->r, hi1);
	set_reg_val(s->r, lo1, val);
	s->pc = ftpc;
	break;

	#if 0
    case I_IRMOVL:
	if (!ok1) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address\n", s->pc);
	    return EXC_ADDR;
	}
	if (!okc) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address",
			s->pc);
	    return EXC_INSTR;
	}
	if (lo1 >= 8) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid register ID 0x%.1x\n",
			s->pc, lo1);
	    return EXC_INSTR;
	}
	set_reg_val(s->r, lo1, cval);
	s->pc = ftpc;
	break;
	#endif
	
    case I_RMMOVL:
	if (!ok1) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address\n", s->pc);
	    return EXC_ADDR;
	}
	if (!okc) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address\n", s->pc);
	    return EXC_INSTR;
	}
	if (hi1 >= 8) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid register ID 0x%.1x\n",
			s->pc, hi1);
	    return EXC_INSTR;
	}
	if (lo1 < 8) 
	    cval += get_reg_val(s->r, lo1);
	val = get_reg_val(s->r, hi1);
	if (!set_word_val(s->m, cval, val)) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid data address 0x%x\n",
			s->pc, cval);
	    return EXC_ADDR;
	}
	s->pc = ftpc;
	break;
    case I_MRMOVL:
	if (!ok1) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address\n", s->pc);
	    return EXC_ADDR;
	}
	if (!okc) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction addres\n", s->pc);
	    return EXC_INSTR;
	}
	if (hi1 >= 8) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid register ID 0x%.1x\n",
			s->pc, hi1);
	    return EXC_INSTR;
	}
	if (lo1 < 8) 
	    cval += get_reg_val(s->r, lo1);
	if (!get_word_val(s->m, cval, &val))
	    return EXC_ADDR;
	set_reg_val(s->r, hi1, val);
	s->pc = ftpc;
	break;
    case I_ALU:
	if (!ok1) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address\n", s->pc);
	    return EXC_ADDR;
	}
	argA = get_reg_val(s->r, hi1);
	argB = get_reg_val(s->r, lo1);
	val = compute_alu(lo0, argA, argB);
	set_reg_val(s->r, lo1, val);
	s->cc = compute_cc(lo0, argA, argB);
	s->pc = ftpc;
	break;
    case I_JXX:
	if (!ok1) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address\n", s->pc);
	    return EXC_ADDR;
	}
	if (!okc) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address\n", s->pc);
	    return EXC_ADDR;
	}
	if (take_branch(s->cc, lo0))
	    s->pc = cval;
	else
	    s->pc = ftpc;
	break;
    #if 0
    case I_CALL:
	if (!ok1) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address\n", s->pc);
	    return EXC_ADDR;
	}
	if (!okc) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address\n", s->pc);
	    return EXC_ADDR;
	}
	val = get_reg_val(s->r, REG_ESP) - 4;
	set_reg_val(s->r, REG_ESP, val);
	if (!set_word_val(s->m, val, ftpc)) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid stack address 0x%x\n", s->pc, val);
	    return EXC_ADDR;
	}
	s->pc = cval;
	break;
    case I_RET:
	/* Return Instruction.  Pop address from stack */
	dval = get_reg_val(s->r, REG_ESP);
	if (!get_word_val(s->m, dval, &val)) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid stack address 0x%x\n",
			s->pc, dval);
	    return EXC_ADDR;
	}
	set_reg_val(s->r, REG_ESP, dval + 4);
	s->pc = val;
	break;
    #endif
    case I_PUSHL:
	if (!ok1) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address\n", s->pc);
	    return EXC_ADDR;
	}
	if (hi1 >= 8) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid register ID 0x%.1x\n", s->pc, hi1);
	    return EXC_INSTR;
	}
	val = get_reg_val(s->r, hi1);
	dval = get_reg_val(s->r, REG_ESP) - 4;
	set_reg_val(s->r, REG_ESP, dval);
	if  (!set_word_val(s->m, dval, val)) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid stack address 0x%x\n", s->pc, dval);
	    return EXC_ADDR;
	}
	s->pc = ftpc;
	break;
    case I_POPL:
	if (!ok1) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address\n", s->pc);
	    return EXC_ADDR;
	}
	if (hi1 >= 8) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid register ID 0x%.1x\n", s->pc, hi1);
	    return EXC_INSTR;
	}
	dval = get_reg_val(s->r, REG_ESP);
	set_reg_val(s->r, REG_ESP, dval+4);
	if (!get_word_val(s->m, dval, &val)) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid stack address 0x%x\n",
			s->pc, dval);
	    return EXC_ADDR;
	}
	set_reg_val(s->r, hi1, val);
	s->pc = ftpc;
	break;
    case I_LEAVE:
	dval = get_reg_val(s->r, REG_EBP);
	set_reg_val(s->r, REG_ESP, dval+4);
	if (!get_word_val(s->m, dval, &val)) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid stack address 0x%x\n",
			s->pc, dval);
	    return EXC_ADDR;
	}
	set_reg_val(s->r, REG_EBP, val);
	s->pc = ftpc;
	break;

	#if 0
    case I_ALUI:
	if (!ok1) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address\n", s->pc);
	    return EXC_ADDR;
	}
	if (!okc) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address",
			s->pc);
	    return EXC_INSTR;
	}
	if (lo1 >= 8) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid register ID 0x%.1x\n",
			s->pc, lo1);
	    return EXC_INSTR;
	}
	argB = get_reg_val(s->r, lo1);
	val = argB + cval;
	set_reg_val(s->r, lo1, val);
	s->cc = compute_cc(A_ADD, cval, argB);
	s->pc = ftpc;
	break;
	#endif
	
    default:
	if (error_file)
	    fprintf(error_file,
		    "PC = 0x%x, Invalid instruction %.2x\n", s->pc, byte0);
	return EXC_INSTR;
    }
    return EXC_NONE;
}
Ejemplo n.º 10
0
/* Return resulting exception status */
static exc_t sim_step()
{
    word_t aluA;
    word_t aluB;
    word_t alufun;
    exc_t status = update_state(); /* Update state from last cycle */

    if (plusmode) {
	pc = gen_pc();
    }
    valp = pc;
    if (get_byte_val(mem, valp, &instr)) {
	icode = HI4(instr);
	ifun = LO4(instr);
    } else {
	instr = HPACK(I_NOP,0);
	icode = I_NOP;
	ifun = 0;
	status = EXC_ADDR;
	sim_log("Couldn't fetch at address 0x%x\n", valp);
    }
    valp++;
    if (gen_need_regids()) {
	byte_t regids;
	if (get_byte_val(mem, valp, &regids)) {
	    ra = GET_RA(regids);
	    rb = GET_RB(regids);
	} else {
	    ra = REG_NONE;
	    rb = REG_NONE;
	    status = EXC_ADDR;
	    sim_log("Couldn't fetch at address 0x%x\n", valp);
	}
	valp++;
    } else {
	ra = REG_NONE;
	rb = REG_NONE;
    }

    if (gen_need_valC()) {
	if (get_word_val(mem, valp, &valc)) {
	} else {
	    valc = 0;
	    status = EXC_ADDR;
	    sim_log("Couldn't fetch at address 0x%x\n", valp);
	}
	valp+=4;
    } else {
	valc = 0;
    }

    if (status == EXC_NONE && !gen_instr_valid()) {
	status = EXC_INSTR;
    }

    sim_log("IF: Fetched %s at 0x%x.  ra=%s, rb=%s, valC = 0x%x\n",
	    iname(HPACK(icode,ifun)), pc, reg_name(ra), reg_name(rb), valc);

    if (status == EXC_NONE && icode == I_HALT) {
	status = EXC_HALT;
    }
    
    srcA = gen_srcA();
    if (srcA != REG_NONE) {
	vala = get_reg_val(reg, srcA);
    } else {
	vala = 0;
    }
    
    srcB = gen_srcB();
    if (srcB != REG_NONE) {
	valb = get_reg_val(reg, srcB);
    } else {
	valb = 0;
    }

    destE = gen_dstE();
    destM = gen_dstM();

    aluA = gen_aluA();
    aluB = gen_aluB();
    alufun = gen_alufun();
    vale = compute_alu(alufun, aluA, aluB);
    cc_in = cc;
    if (gen_set_cc())
	cc_in = compute_cc(alufun, aluA, aluB);

    bcond = (icode == I_JMP) && take_branch(cc, ifun);

    mem_addr = gen_mem_addr();
    mem_data = gen_mem_data();

    if (status == EXC_NONE && gen_mem_read()) {
	if (!get_word_val(mem, mem_addr, &valm)) {
	    sim_log("Couldn't read at address 0x%x\n", mem_addr);
	    return EXC_ADDR;
	}
    } else
	valm = 0;

    mem_write = status == EXC_NONE && gen_mem_write();

    if (plusmode) {
	prev_icode_in = icode;
	prev_ifun_in = ifun;
	prev_valc_in = valc;
	prev_valm_in = valm;
	prev_valp_in = valp;
	prev_bcond_in = bcond;
    } else {
	/* Update PC */
	pc_in = gen_new_pc();
    } 
    sim_report();
    return status;
}
Ejemplo n.º 11
0
void do_if_stage()
{
    exc_t nstatus = EXC_NONE;
    word_t fetchpc = gen_f_pc();
    word_t valp = fetchpc;
    bool_t fetch_ok;
    byte_t instr;
    byte_t regids = HPACK(REG_NONE, REG_NONE);
    word_t valc = 0;

    f_pc = fetchpc;

    if (fetchpc == 0) {
	sim_log("Fetch: Fetch pc = 0, nominal pc = 0x%x\n",
		pc_curr->pc);
    }

    /* Ready to fetch instruction.  Speculatively fetch register byte
       and immediate word
    */
    fetch_ok = get_byte_val(mem, valp, &instr);
    if (fetch_ok) {
	if_id_next->icode = GET_ICODE(instr);
	if_id_next->ifun = GET_FUN(instr);
    } else {
	if_id_next->icode = I_NOP;
	if_id_next->ifun = 0;
	nstatus = EXC_ADDR;
    }
    valp++;
    if (fetch_ok && gen_need_regids()) {
	fetch_ok = get_byte_val(mem, valp, &regids);
	valp ++;
    }
    if_id_next->ra = HI4(regids);
    if_id_next->rb = LO4(regids);
    if (fetch_ok && gen_need_valC()) {
	fetch_ok = get_word_val(mem, valp, &valc);
	valp+= 4;
    }
    if_id_next->valp = valp;
    if_id_next->valc = valc;

    pc_next->pc = gen_new_F_predPC();

    if (!gen_instr_valid())
	{
	    byte_t instr = HPACK(if_id_next->icode, if_id_next->ifun);
	    sim_log("Fetch: Instruction code %s (0x%x) invalid\n",
		    iname(instr), instr);
	    nstatus = EXC_INSTR;
	}

    pc_next->exception = (nstatus == EXC_NONE) ? EXC_NONE : EXC_BUBBLE;

    if_id_next->stage_pc = fetchpc;
    if_id_next->exception = nstatus;

    /* Recompute icode for one-write implementation of popl */
    if_id_next->icode = gen_new_D_icode();

    sim_log("Fetch: Fetched %s at 0x%x, ra = %s, rb = %s, valp = 0x%x, status = %s\n",
	    iname(HPACK(if_id_next->icode, if_id_next->ifun)),
	    if_id_next->stage_pc,
	    reg_name(if_id_next->ra), reg_name(if_id_next->rb),
	    if_id_next->valp,
	    exc_name(nstatus));
}
Ejemplo n.º 12
0
/* Execute single instruction.  Return status. */
stat_t step_state(state_ptr s, FILE *error_file)
{
    word_t argA, argB;
    byte_t byte0 = 0;
    byte_t byte1 = 0;
    itype_t hi0;
    alu_t  lo0;
    reg_id_t hi1 = REG_NONE;
    reg_id_t lo1 = REG_NONE;
    bool_t ok1 = TRUE;
    word_t cval = 0;
    word_t okc = TRUE;
    word_t val, dval;
    bool_t need_regids;
    bool_t need_imm;
    word_t ftpc = s->pc;  /* Fall-through PC */

    if (!get_byte_val(s->m, ftpc, &byte0)) {
	if (error_file)
	    fprintf(error_file,
		    "PC = 0x%x, Invalid instruction address\n", s->pc);
	return STAT_ADR;
    }
    ftpc++;

    hi0 = HI4(byte0);
    lo0 = LO4(byte0);

    need_regids =
	(hi0 == I_RRMOVL || hi0 == I_ALU || hi0 == I_PUSHL ||
	 hi0 == I_POPL || hi0 == I_IRMOVL || hi0 == I_RMMOVL ||
	 hi0 == I_MRMOVL || hi0 == I_IADDL || hi0 == I_ISUBL);

    if (need_regids) {
	ok1 = get_byte_val(s->m, ftpc, &byte1);
	ftpc++;
	hi1 = HI4(byte1);
	lo1 = LO4(byte1);
    }

    need_imm =
	(hi0 == I_IRMOVL || hi0 == I_RMMOVL || hi0 == I_MRMOVL ||
	 hi0 == I_JMP || hi0 == I_CALL || hi0 == I_IADDL || hi0 == I_ISUBL);

    if (need_imm) {
	okc = get_word_val(s->m, ftpc, &cval);
	ftpc += 4;
    }

    switch (hi0) {
    case I_NOP:
	s->pc = ftpc;
	break;
    case I_HALT:
	return STAT_HLT;
	break;
    case I_RRMOVL:  /* Both unconditional and conditional moves */
	if (!ok1) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address\n", s->pc);
	    return STAT_ADR;
	}
	if (!reg_valid(hi1)) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid register ID 0x%.1x\n",
			s->pc, hi1);
	    return STAT_INS;
	}
	if (!reg_valid(lo1)) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid register ID 0x%.1x\n",
			s->pc, lo1);
	    return STAT_INS;
	}
	val = get_reg_val(s->r, hi1);
	if (cond_holds(s->cc, lo0))
	  set_reg_val(s->r, lo1, val);
	s->pc = ftpc;
	break;
    case I_IRMOVL:
	if (!ok1) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address\n", s->pc);
	    return STAT_ADR;
	}
	if (!okc) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address",
			s->pc);
	    return STAT_INS;
	}
	if (!reg_valid(lo1)) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid register ID 0x%.1x\n",
			s->pc, lo1);
	    return STAT_INS;
	}
	set_reg_val(s->r, lo1, cval);
	s->pc = ftpc;
	break;
    case I_RMMOVL:
	if (!ok1) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address\n", s->pc);
	    return STAT_ADR;
	}
	if (!okc) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address\n", s->pc);
	    return STAT_INS;
	}
	if (!reg_valid(hi1)) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid register ID 0x%.1x\n",
			s->pc, hi1);
	    return STAT_INS;
	}
	if (reg_valid(lo1)) 
	    cval += get_reg_val(s->r, lo1);
	val = get_reg_val(s->r, hi1);
	if (!set_word_val(s->m, cval, val)) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid data address 0x%x\n",
			s->pc, cval);
	    return STAT_ADR;
	}
	s->pc = ftpc;
	break;
    case I_MRMOVL:
	if (!ok1) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address\n", s->pc);
	    return STAT_ADR;
	}
	if (!okc) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction addres\n", s->pc);
	    return STAT_INS;
	}
	if (!reg_valid(hi1)) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid register ID 0x%.1x\n",
			s->pc, hi1);
	    return STAT_INS;
	}
	if (reg_valid(lo1)) 
	    cval += get_reg_val(s->r, lo1);
	if (!get_word_val(s->m, cval, &val))
	    return STAT_ADR;
	set_reg_val(s->r, hi1, val);
	s->pc = ftpc;
	break;
    case I_ALU:
	if (!ok1) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address\n", s->pc);
	    return STAT_ADR;
	}
	argA = get_reg_val(s->r, hi1);
	argB = get_reg_val(s->r, lo1);
	val = compute_alu(lo0, argA, argB);
	set_reg_val(s->r, lo1, val);
	s->cc = compute_cc(lo0, argA, argB);
	s->pc = ftpc;
	break;
    case I_JMP:
	if (!ok1) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address\n", s->pc);
	    return STAT_ADR;
	}
	if (!okc) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address\n", s->pc);
	    return STAT_ADR;
	}
	if (cond_holds(s->cc, lo0))
	    s->pc = cval;
	else
	    s->pc = ftpc;
	break;
    case I_CALL:
	if (!ok1) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address\n", s->pc);
	    return STAT_ADR;
	}
	if (!okc) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address\n", s->pc);
	    return STAT_ADR;
	}
	val = get_reg_val(s->r, REG_ESP) - 4;
	set_reg_val(s->r, REG_ESP, val);
	if (!set_word_val(s->m, val, ftpc)) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid stack address 0x%x\n", s->pc, val);
	    return STAT_ADR;
	}
	s->pc = cval;
	break;
    case I_RET:
	/* Return Instruction.  Pop address from stack */
	dval = get_reg_val(s->r, REG_ESP);
	if (!get_word_val(s->m, dval, &val)) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid stack address 0x%x\n",
			s->pc, dval);
	    return STAT_ADR;
	}
	set_reg_val(s->r, REG_ESP, dval + 4);
	s->pc = val;
	break;
    case I_PUSHL:
	if (!ok1) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address\n", s->pc);
	    return STAT_ADR;
	}
	if (!reg_valid(hi1)) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid register ID 0x%.1x\n", s->pc, hi1);
	    return STAT_INS;
	}
	val = get_reg_val(s->r, hi1);
	dval = get_reg_val(s->r, REG_ESP) - 4;
	set_reg_val(s->r, REG_ESP, dval);
	if  (!set_word_val(s->m, dval, val)) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid stack address 0x%x\n", s->pc, dval);
	    return STAT_ADR;
	}
	s->pc = ftpc;
	break;
    case I_POPL:
	if (!ok1) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address\n", s->pc);
	    return STAT_ADR;
	}
	if (!reg_valid(hi1)) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid register ID 0x%.1x\n", s->pc, hi1);
	    return STAT_INS;
	}
	dval = get_reg_val(s->r, REG_ESP);
	set_reg_val(s->r, REG_ESP, dval+4);
	if (!get_word_val(s->m, dval, &val)) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid stack address 0x%x\n",
			s->pc, dval);
	    return STAT_ADR;
	}
	set_reg_val(s->r, hi1, val);
	s->pc = ftpc;
	break;
    case I_LEAVE:
	dval = get_reg_val(s->r, REG_EBP);
	set_reg_val(s->r, REG_ESP, dval+4);
	if (!get_word_val(s->m, dval, &val)) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid stack address 0x%x\n",
			s->pc, dval);
	    return STAT_ADR;
	}
	set_reg_val(s->r, REG_EBP, val);
	s->pc = ftpc;
	break;
    case I_IADDL:
	if (!ok1) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address\n", s->pc);
	    return STAT_ADR;
	}
	if (!okc) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address",
			s->pc);
	    return STAT_INS;
	}
	if (!reg_valid(lo1)) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid register ID 0x%.1x\n",
			s->pc, lo1);
	    return STAT_INS;
	}
	argB = get_reg_val(s->r, lo1);
	val = argB + cval;
	set_reg_val(s->r, lo1, val);
	s->cc = compute_cc(A_ADD, cval, argB);
	s->pc = ftpc;
	break;
     case I_ISUBL:
	if (!ok1) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address\n", s->pc);
	    return STAT_ADR;
	}
	if (!okc) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid instruction address",
			s->pc);
	    return STAT_INS;
	}
	if (!reg_valid(lo1)) {
	    if (error_file)
		fprintf(error_file,
			"PC = 0x%x, Invalid register ID 0x%.1x\n",
			s->pc, lo1);
	    return STAT_INS;
	}
	argB = get_reg_val(s->r, lo1);
	val = argB - cval;
	set_reg_val(s->r, lo1, val);
	s->cc = compute_cc(A_SUB, cval, argB);
	s->pc = ftpc;
	break;
    default:
	if (error_file)
	    fprintf(error_file,
		    "PC = 0x%x, Invalid instruction %.2x\n", s->pc, byte0);
	return STAT_INS;
    }
    return STAT_AOK;
}
Ejemplo n.º 13
0
Archivo: ssim.c Proyecto: Azard/icslabs
/* Return resulting status */
static byte_t sim_step()
{
    word_t aluA;
    word_t aluB;
    word_t alufun;

    status = STAT_AOK;
    imem_error = dmem_error = FALSE;

    update_state(); /* Update state from last cycle */

    if (plusmode) {
	pc = gen_pc();
    }
    valp = pc;
    instr = HPACK(I_NOP, F_NONE);
    imem_error = !get_byte_val(mem, valp, &instr);
    if (imem_error) {
	sim_log("Couldn't fetch at address 0x%x\n", valp);
    }
    imem_icode = HI4(instr);
    imem_ifun = LO4(instr);
    icode = gen_icode();
    ifun  = gen_ifun();
    instr_valid = gen_instr_valid();
    valp++;
    if (gen_need_regids()) {
	byte_t regids;
	if (get_byte_val(mem, valp, &regids)) {
	    ra = GET_RA(regids);
	    rb = GET_RB(regids);
	} else {
	    ra = REG_NONE;
	    rb = REG_NONE;
	    status = STAT_ADR;
	    sim_log("Couldn't fetch at address 0x%x\n", valp);
	}
	valp++;
    } else {
	ra = REG_NONE;
	rb = REG_NONE;
    }

    if (gen_need_valC()) {
	if (get_word_val(mem, valp, &valc)) {
	} else {
	    valc = 0;
	    status = STAT_ADR;
	    sim_log("Couldn't fetch at address 0x%x\n", valp);
	}
	valp+=4;
    } else {
	valc = 0;
    }
    sim_log("IF: Fetched %s at 0x%x.  ra=%s, rb=%s, valC = 0x%x\n",
	    iname(HPACK(icode,ifun)), pc, reg_name(ra), reg_name(rb), valc);

    if (status == STAT_AOK && icode == I_HALT) {
	status = STAT_HLT;
    }
    
    srcA = gen_srcA();
    if (srcA != REG_NONE) {
	vala = get_reg_val(reg, srcA);
    } else {
	vala = 0;
    }
    
    srcB = gen_srcB();
    if (srcB != REG_NONE) {
	valb = get_reg_val(reg, srcB);
    } else {
	valb = 0;
    }

    cond = cond_holds(cc, ifun);

    destE = gen_dstE();
    destM = gen_dstM();

    aluA = gen_aluA();
    aluB = gen_aluB();
    alufun = gen_alufun();
    vale = compute_alu(alufun, aluA, aluB);
    cc_in = cc;
    if (gen_set_cc())
	cc_in = compute_cc(alufun, aluA, aluB);

    bcond =  cond && (icode == I_JMP);

    mem_addr = gen_mem_addr();
    mem_data = gen_mem_data();


    if (gen_mem_read()) {
      dmem_error = dmem_error || !get_word_val(mem, mem_addr, &valm);
      if (dmem_error) {
	sim_log("Couldn't read at address 0x%x\n", mem_addr);
      }
    } else
      valm = 0;

    mem_write = gen_mem_write();
    if (mem_write) {
      /* Do a test read of the data memory to make sure address is OK */
      word_t junk;
      dmem_error = dmem_error || !get_word_val(mem, mem_addr, &junk);
    }

    status = gen_Stat();

    if (plusmode) {
	prev_icode_in = icode;
	prev_ifun_in = ifun;
	prev_valc_in = valc;
	prev_valm_in = valm;
	prev_valp_in = valp;
	prev_bcond_in = bcond;
    } else {
	/* Update PC */
	pc_in = gen_new_pc();
    } 
    sim_report();
    return status;
}
Ejemplo n.º 14
0
void
bsbport_poll_cb(void)
{
  BSBDEBUG("MQTT Poll");
  for (uint8_t i = 0; i < BSBPORT_MESSAGE_BUFFER_LEN; i++)
  {
    if (bsbport_msg_buffer.msg[i].mqtt_new)
    {
      uint8_t len;
      uint8_t topic_len;
      char buf[DATA_LENGTH];
      char topic[TOPIC_LENGTH];

      bsbport_msg_buffer.msg[i].mqtt_new = 0;

      // Topic
      topic_len = snprintf_P(topic, TOPIC_LENGTH, publish_topic_format,
                 LO4(bsbport_msg_buffer.msg[i].src),
                 bsbport_msg_buffer.msg[i].p.data.p1,
                 bsbport_msg_buffer.msg[i].p.data.p2,
                 bsbport_msg_buffer.msg[i].p.data.p3,
                 bsbport_msg_buffer.msg[i].p.data.p4);

      // RAW
      strncat_P(topic, PSTR("RAW"), TOPIC_LENGTH - topic_len - 1); 
      len =
        snprintf_P(buf, DATA_LENGTH, PSTR("%u"),
                   bsbport_msg_buffer.msg[i].value);
      mqtt_construct_publish_packet(topic, buf, len, BSBPORT_MQTT_RETAIN);
      BSBDEBUG("%s=%s", topic, buf);

      // STA
      topic[topic_len]=0;
      strncat_P(topic, PSTR("STA"), TOPIC_LENGTH - topic_len - 1); 
      len =
        snprintf_P(buf, DATA_LENGTH, PSTR("%u"),
                   HI8(bsbport_msg_buffer.msg[i].value));
      mqtt_construct_publish_packet(topic, buf, len, BSBPORT_MQTT_RETAIN);
      BSBDEBUG("%s=%s", topic, buf);

      // TMP
      topic[topic_len]=0;
      strncat_P(topic, PSTR("TMP"), TOPIC_LENGTH - topic_len - 1); 
      len =
        itoa_fixedpoint(((int32_t) bsbport_msg_buffer.msg[i].value * 100) /
                        64, 2, buf, DATA_LENGTH);
      mqtt_construct_publish_packet(topic, buf, len, BSBPORT_MQTT_RETAIN);
      BSBDEBUG("%s=%s", topic, buf);

      // FP1
      topic[topic_len]=0;
      strncat_P(topic, PSTR("FP1"), TOPIC_LENGTH - topic_len - 1); 
      len =
        itoa_fixedpoint(bsbport_msg_buffer.msg[i].value, 1, buf, DATA_LENGTH);
      mqtt_construct_publish_packet(topic, buf, len, BSBPORT_MQTT_RETAIN);
      BSBDEBUG("%s=%s", topic, buf);

      // FP5
      topic[topic_len]=0;
      strncat_P(topic, PSTR("FP5"), TOPIC_LENGTH - topic_len - 1); 
      len =
        itoa_fixedpoint(bsbport_msg_buffer.msg[i].value * 10 / 2, 1, buf,
                        DATA_LENGTH);
      mqtt_construct_publish_packet(topic, buf, len, BSBPORT_MQTT_RETAIN);
      BSBDEBUG("%s=%s", topic, buf);
    }
  }
}