#define CLOCK 10000000.0
#define CYCLES_PER_SECOND (CLOCK/4)
#define BITS 8 /* plus start/stop bits */
#define IN_BAUDRATE 9600.0
#define OUT_BAUDRATE 31250.0

int loop_no;

void insert_wait(int t) {
  int i;

  if (t == 0)
    return;
  printf("; wait %d\n", t);
  if (t >=4) {
    printf("\tmovlw\tD\'%d\'\n", (t-1)/3);
    printf("\tmovwf\ttemp\n");
    printf("loop%d:\tdecfsz\ttemp,f\n", loop_no);
    printf("\tgoto\tloop%d\n", loop_no);
    loop_no++;
    t -= (t/3)*3-1+2;
  }
  for (i=0; i<t; i++)
    printf("\tnop\n");
}

#define IN_CYCLES 3
int input_bit(int t, int t_ideal, int bit) {
  printf("; CYCLE %d INPUT bit %d", t, bit);
  if (t != t_ideal) 
    printf("(should be CYCLE %d)", t_ideal);
  printf("\n");

  printf("\tmovlw\tD\'%d\'\n", 1<<bit);
  printf("\tbtfsc\tPORTA,WSIN\n");
  printf("\taddwf\txmit,f\n");
  return IN_CYCLES;
}


/* bit = -1: start bit, BITS: stop bit */
int output_bit(int t, int t_ideal, int bit) {
  if (bit == -1)
    printf("; CYCLE %d START bit", t);
  else if (bit == BITS)
    printf("; CYCLE %d STOP bit", t);
  else
    printf("; CYCLE %d OUTPUT bit %d", t, bit);
  if (t != t_ideal) 
    printf("(should be CYCLE %d)", t_ideal);
  printf("\n");

  if (bit == -1) {
    printf("\tbcf\tPORTA,MIDIOUT\n");
    return 1;
  }
  if (bit == BITS) {
    printf("\tbsf\tPORTA,MIDIOUT\n");
    return 1;
  }

  printf("\tbtfsc\txmit,%d\n", bit);
  printf("\tbsf\tPORTA,MIDIOUT\n");
  printf("\tbtfss\txmit,%d\n", bit);
  printf("\tbcf\tPORTA,MIDIOUT\n");
  return 4;
}

int main() {
  int i, j, t, t0;
  int in_cycle[BITS+2];
  int out_cycle[BITS+3];

  in_cycle[0] = 0;
  for (i=1; i < BITS+2; i++)
    in_cycle[i] = 
      (int) (CYCLES_PER_SECOND * (i+0.5)/IN_BAUDRATE);

  for (i=0; i < BITS+3; i++) 
    out_cycle[i] = in_cycle[BITS+1]
      + (int) (CYCLES_PER_SECOND * (i-BITS-1)/OUT_BAUDRATE);
    /* so that we can send the stop bit when we are receiving it */

  i=0;
  j=0;
  t=0;
  t0 = t;
  loop_no = 0;
  printf("xmitmidi:\n");
  printf("\tclrf\txmit\n");
  t++;
  t0++;
  while(1) {
    if (i < BITS+2 && t>=in_cycle[i]) {
      insert_wait(t-t0);
      t0 = t;
      if (i > 0 && i <= BITS)
	t0 += input_bit(t, in_cycle[i], i-1);
      t = t0;
      i++;
    } else if (t>=out_cycle[j]) {
      if (j < BITS+2) {
	insert_wait(t-t0);
	t0 = t;
	t0 += output_bit(t, out_cycle[j], j-1);
	t = t0;
	j++;
      } else 
	break;
    } else
      t++;
  }
  /* there should be enough time for stop bit... */
  printf("\treturn\n");
  exit(0);
}
