%i   "acc.sfl"
%i   "alu.sfl"
%i   "ir.sfl"
%i   "pc.sfl"
%i   "sp.sfl"

submod_class acc {
   input     in<8> ;
   output    out<8> ;
   instrin   load ;
   instrin   hold ;
   instrin   reset ;
   instr_arg load(in) ;
   instr_arg hold() ;
   instr_arg reset() ;
   }

submod_class alu {
   input     a<8> ;
   input     b<8> ;
   output    out<8> ;
   output    zero ;
   instrin   trans_a ;
   instrin   trans_b ;
   instrin   add ;
   instrin   and ;
   instrin   xor ;
   instr_arg trans_a(a) ;
   instr_arg trans_b(b) ;
   instr_arg add(a,b) ;
   instr_arg and(a,b) ;
   instr_arg xor(a,b) ;
   }

submod_class ir {
   input     in<8> ;
   output    out<8> ;
   instrin   load ;
   instrin   hold ;
   instrin   reset ;
   instr_arg load(in) ;
   instr_arg hold() ;
   instr_arg reset() ;
   }

submod_class pc {
   input     in<8> ;
   output    out<8> ;
   instrin   load ;
   instrin   inc ;
   instrin   hold ;
   instrin   reset ;
   instr_arg load(in) ;
   instr_arg hold() ;
   instr_arg inc() ;
   instr_arg reset() ;
   }

submod_class sp {
   output    out<8> ;
   instrin   dec ;
   instrin   inc ;
   instrin   reset ;
   instrin   hold ;
   instr_arg dec() ;
   instr_arg inc() ;
   instr_arg reset() ;
   instr_arg hold() ;
   }

module   inside {
   input     in_data<8> ;
   output    out_data<8> ;
   output    address<8> ;
   tmp       oprand<8> ;
   tmp       opcode<8> ;
   tmp       pc_out<8> ;
   tmp       alu_out<8> ;
   tmp       acc_out<8> ;
   tmp       sp_out<8> ;
/*
*/
   output    acc_a<8>,pc_a<8>,sp_a<8> ;
   instrin   reset ;
   instrin   start ;
   instrout  read ;
   instrout  write ;
   acc       acc0 ;
   alu       alu0 ;
   ir        ir0,ir1 ;
   pc        pc0 ;
   sp        sp0 ;
   stage_name   fetch_exec {
      task   run() ;
      }
   
   instruct reset
      par {
        /* reset registers */
        acc_out = acc0.reset().out ;
        pc_out  = pc0.reset().out ;
        sp_out  = sp0.reset().out ;
        ir0.reset() ;
        ir1.reset() ;
        /* read mode for RAM */
        read() ;
        /* drive output terminals */
        alu_out = alu0.trans_a(in_data).out ;
        out_data = alu_out ;
        address = pc_out ;
        /* for monitoring */
/*
*/
        acc_a = acc_out ;
        pc_a  = pc_out ;
        sp_a  = sp_out ;
        }

   instruct start
      generate fetch_exec.run() ;

   stage fetch_exec {
      state_name  fetch0 ;
      state_name  fetch1 ;
      state_name  exec ;
      first_state fetch0 ;

      state fetch0
      /* instruction fetch state phase I */
        par {
           /* increment program counter for next instruction */
           pc_out = pc0.inc().out ;
           acc_out = acc0.hold().out ;
           sp_out = sp0.hold().out ;
           alu_out = alu0.trans_a(in_data).out ;
           /* drive output terminals */
           address = pc_out ;
           out_data = alu_out ;
           /* read mode for RAM */
           read() ;
           /* load instruction register from RAM */
           ir0.load(in_data) ;
           /* for monitoring */
/*
*/
           acc_a = acc_out ;
           pc_a = pc_out ;
           sp_a = sp_out ;
           goto fetch1 ;
           }
      state fetch1
      /* instruction fetch state phase II */
        par {
           /* increment program counter for next instruction */
           pc_out = pc0.inc().out ;
           acc_out = acc0.hold().out ;
           sp_out = sp0.hold().out ;
           alu_out = alu0.trans_a(in_data).out ;
           /* drive output terminals */
           address = pc_out ;
           out_data = alu_out ;
           /* read mode for RAM */
           read() ;
           /* load instruction register from RAM */
           ir1.load(in_data) ;
           /* for monitoring */
/*
*/
           acc_a = acc_out ;
           pc_a = pc_out ;
           sp_a = sp_out ;
           goto exec ;
           }
      state exec
      /* execution stage */
        par {
           opcode = ir0.hold().out ;
           oprand = ir1.hold().out ;
           /* drive output terminals */
           /* for monitoring */
/*
*/
           acc_a = acc_out ;
           pc_a  = pc_out ;
           sp_a  = sp_out ;
           /* instruction set */
           any {
              opcode == 0b00000000 : 
                /* load acc */
                par {
                  read() ;
                  alu_out  = alu0.trans_a(in_data).out ;
                  acc_out  = acc0.load(alu_out).out ;
                  pc_out   = pc0.hold().out ;
                  sp_out   = sp0.hold().out ;
                  out_data = alu_out ;
                  address  = oprand ;
                   }
              opcode == 0b00000001 :
                /* add acc */
                par {
                  read() ;
                  alu_out  = alu0.add(in_data,acc_out).out ;
                  acc_out  = acc0.load(alu_out).out ;
                  pc_out   = pc0.hold().out ;
                  sp_out   = sp0.hold().out ;
                  out_data = alu_out ;
                  address  = oprand ;
                    }
              opcode == 0b00000010 :
                /* jump */
                par {
                  read() ;
                  pc0.load(oprand) ;
                  alu_out   = alu0.trans_a(in_data).out ;
                  pc_out    = pc0.hold().out ;
                  acc_out   = acc0.hold().out ;
                  sp_out    = sp0.hold().out ;
                  out_data  = alu_out ;
                  address   = oprand ;
                  }
              opcode == 0b00000011 : 
                par {
                  read() ;
                  alu_out  = alu0.trans_a(in_data).out ;
                  pc_out   = pc0.hold().out ;
                  acc_out  = acc0.hold().out ;
                  sp_out   = sp0.hold().out ;
                  out_data = alu_out ;
                  address  = oprand ;
                  }
              opcode == 0b00000100 : 
                par {
                  read() ;
                  alu_out  = alu0.trans_a(in_data).out ;
                  pc_out   = pc0.hold().out ;
                  acc_out  = acc0.hold().out ;
                  sp_out   = sp0.hold().out ;
                  out_data = alu_out ;
                  address  = oprand ;
                  }
              opcode == 0b00000101 : 
                par {
                  read() ;
                  alu_out  = alu0.trans_a(in_data).out ;
                  pc_out   = pc0.hold().out ;
                  acc_out  = acc0.hold().out ;
                  sp_out   = sp0.hold().out ;
                  out_data = alu_out ;
                  address  = oprand ;
                  }
              opcode == 0b00000110 : 
                par {
                  read() ;
                  alu_out  = alu0.trans_a(in_data).out ;
                  pc_out   = pc0.hold().out ;
                  acc_out  = acc0.hold().out ;
                  sp_out   = sp0.hold().out ;
                  out_data = alu_out ;
                  address  = oprand ;
                  }
              opcode == 0b00000111 : 
                par {
                  read() ;
                  alu_out  = alu0.trans_a(in_data).out ;
                  pc_out   = pc0.hold().out ;
                  acc_out  = acc0.hold().out ;
                  sp_out   = sp0.hold().out ;
                  out_data = alu_out ;
                  address  = oprand ;
                  }
              opcode == 0b10000000 :
              /* push */ 
                par {
                  write() ;
                  alu_out  = alu0.trans_a(in_data).out ;
                  pc_out   = pc0.hold().out ;
                  acc_out  = acc0.hold().out ;
                  sp_out   = sp0.dec().out ;
                  out_data = pc_out ;
                  address  = sp_out ;
                  }
              opcode == 0b10000001 :
              /* pop */ 
                par {
                  read() ;
                  alu_out  = alu0.trans_a(in_data).out ;
                  pc_out   = pc0.load(in_data).out ;
                  acc_out  = acc0.hold().out ;
                  sp_out   = sp0.inc().out ;
                  out_data = alu_out ;
                  address  = sp_out ;
                  }
              }
           /* for the next instruction */
           goto fetch0 ;
           }
        }
     }