#include <stdio.h>
#include "test.upe.c"

#define MEM_SIZE	100000

void upe_proc_low_mem (void) {
  fprintf (stderr, "Not enough memory!\n");
  exit (1);
}

unsigned char *upe_proc_mem_pool_0;

int main (void) {
  upe_number_t *from, *to; upe_u32_t n1, n2;

  if (!(upe_proc_mem = upe_create_mem (1))) upe_proc_low_mem ();
  
  from = upe_initnum (32, 0, UPE_NO_SIGN);
  to = upe_initnum (32, 0, UPE_NO_SIGN);
  
  if (!(upe_proc_mem_pool_0 = malloc (UPE_NUM_OF_BYTES (MEM_SIZE * upe_byte_size, CHARBITS)))) upe_proc_low_mem ();
  
  upe_setnum (from, 0);
  upe_setnum (to, 99999);
  upe_map_mem (upe_proc_mem, 0, from, to, upe_proc_mem_pool_0, 1, NULL, 1, NULL);

  upe_donenum (from);
  upe_donenum (to);

  if (upe_proc_init ()) {
    printf ("Error initialising processor\n");
    exit (1);
  }
  
#define I_ARG_N		0
#define I_HALT		0

#define I_ARG_R		1
#define I_INC		0
#define I_DEC		1
#define I_JMP		2
#define I_JO		4
#define I_JU		5
#define I_JZ		6
#define I_JNO		12
#define I_JNU		13
#define I_JNZ		14

#define I_ARG_RD	2
#define I_LD		0
#define I_SHL		2
#define I_SHR		3

#define I_ARG_RR	2
#define I_ST		1

#define I_ARG_RRR	4
#define I_ADD		4
#define I_SUB		5

#define I_ARG_RI	8

  /*
   *  r1 = [1000] * [1004]
   *
   *  0 ld r6, 1000
   *  4 ld r4, [r6]
   *  8 ld r5, 4
   * 12 add r6, r6, r5
   * 16 ld r5, [r6]
   * 20 ld r1, r0
   * 24 add r4, r4, r0		# test if r4 is zero
   * 28 ld r7, 52
   * 32 jz r7
   * 36 add r1, r1, r5
   * 40 dec r4
   * 44 ld r7, 36
   * 48 jnz r7
   * 52 halt
   *
   */

  { unsigned char prg[] = {
      I_ARG_RD | (I_LD << 4), 6, 232, 3,
      I_ARG_RI | (I_LD << 4), 4, 6, 0,
      I_ARG_RD | (I_LD << 4), 5, 4, 0,
      I_ARG_RRR | (I_ADD << 4), 6, 6, 5,
      I_ARG_RI | (I_LD << 4), 5, 6, 0,
      I_ARG_RR | (I_LD << 4), 1, 0, 0,
      I_ARG_RRR | (I_ADD << 4), 4, 4, 0,
      I_ARG_RD | (I_LD << 4), 7, 52, 0,
      I_ARG_R | (I_JZ << 4), 7, 0, 0,
      I_ARG_RRR | (I_ADD << 4), 1, 1, 5,
      I_ARG_R | (I_DEC << 4), 4, 0, 0,
      I_ARG_RD | (I_LD << 4), 7, 36, 0,
      I_ARG_R | (I_JNZ << 4), 7, 0, 0,
      I_ARG_N | (I_HALT << 4), 0, 0, 0,
    };
    int i;
  
    for (i = 0; i < 56; i++) upe_proc_mem_pool_0[i] = prg[i];
  }
  
  printf ("
upecc 1.0 test (c)2000 Stepan Roh

2 numbers will be multiplied by test processor and its assembler program

    0 ld r6, 1000
    4 ld r4, [r6]
    8 ld r5, 4
   12 add r6, r6, r5
   16 ld r5, [r6]
   20 ld r1, r0
   24 add r4, r4, r0
   28 ld r7, 52
   32 jz r7
   36 add r1, r1, r5
   40 dec r4
   44 ld r7, 36
   48 jnz r7
   52 halt

Enter numbers:
");

  scanf ("%lu %lu", &n1, &n2);
  
  upe_proc_mem_pool_0[1000] = n1 & 0xff;
  upe_proc_mem_pool_0[1001] = (n1 >> 8) & 0xff ;
  upe_proc_mem_pool_0[1002] = (n1 >> 16) & 0xff;
  upe_proc_mem_pool_0[1003] = (n1 >> 24) & 0xff;
  
  upe_proc_mem_pool_0[1004] = n2 & 0xff;
  upe_proc_mem_pool_0[1005] = (n2 >> 8) & 0xff ;
  upe_proc_mem_pool_0[1006] = (n2 >> 16) & 0xff;
  upe_proc_mem_pool_0[1007] = (n2 >> 24) & 0xff;
  
  do {
    printf ("IP = %d", upe_getnum (upe_proc_reg_IP));
    printf (" [IP] = %d", upe_proc_mem_pool_0[upe_getnum (upe_proc_reg_IP)]);
    printf (" R1 = %d", upe_getnum (upe_proc_reg_R1));
    printf (" R2 = %d", upe_getnum (upe_proc_reg_R2));
    printf (" R3 = %d", upe_getnum (upe_proc_reg_R3));
    printf (" R4 = %d", upe_getnum (upe_proc_reg_R4));
    printf (" R5 = %d", upe_getnum (upe_proc_reg_R5));
    printf (" R6 = %d", upe_getnum (upe_proc_reg_R6));
    printf (" R7 = %d", upe_getnum (upe_proc_reg_R7));
    printf (" F = %d", upe_getnum (upe_proc_reg_F));
    printf ("\n");
  } while (!upe_proc_step () && !upe_getnum (upe_proc_reg_halt_flag));
  
  printf ("Result of (%lu * %lu) is in R1 : %d\n", n1, n2, upe_getnum (upe_proc_reg_R1));
  
  upe_destroy_mem (upe_proc_mem);
  
  return 0;
}
