* Simulator of microcontrollers (serial.cc)
*
* Copyright (C) 1999,99 Drotos Daniel, Talker Bt.
- *
+ *
* To contact author send email to drdani@mazsola.iit.uni-miskolc.hu
*
*/
02111-1307, USA. */
/*@1@*/
+#include "ddconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#ifdef HAVE_TERMIOS_H
+#include <termios.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <strings.h>
+#include <assert.h>
+
+// prj
+#include "globals.h"
+
+// local
#include "serialcl.h"
#include "regs51.h"
+#include "uc51cl.h"
+#include "cmdutil.h"
cl_serial::cl_serial(class cl_uc *auc):
cl_hw(auc, HW_UART, 0, "uart")
-{}
+{
+ serial_in= serial_out= NIL;
+}
-/*int
+cl_serial::~cl_serial(void)
+{
+ if (serial_in != serial_out && serial_in)
+ {
+#ifdef HAVE_TERMIOS_H
+ if (isatty(fileno(serial_in)))
+ tcsetattr(fileno(serial_in), TCSANOW, &saved_attributes_in);
+#endif
+ fclose(serial_in);
+ }
+ if (serial_out)
+ {
+#ifdef HAVE_TERMIOS_H
+ if (isatty(fileno(serial_out)))
+ tcsetattr(fileno(serial_out), TCSANOW, &saved_attributes_out);
+#endif
+ fclose(serial_out);
+ }
+ delete serial_in_file_option;
+ delete serial_out_file_option;
+}
+
+int
cl_serial::init(void)
{
+#ifdef HAVE_TERMIOS_H
+ int i;
+ struct termios tattr;
+#endif
+
+ set_name("mcs51_uart");
+ sfr= uc->address_space(MEM_SFR_ID);
+ if (sfr)
+ {
+ //sbuf= sfr->register_hw(SBUF, this, 0);
+ //pcon= sfr->register_hw(PCON, this, 0);
+ //scon= sfr->register_hw(SCON, this, 0);
+ register_cell(sfr, SBUF, &sbuf, wtd_restore_write);
+ register_cell(sfr, PCON, &pcon, wtd_restore_write);
+ register_cell(sfr, SCON, &scon, wtd_restore_write);
+ }
+
+ serial_in_file_option= new cl_optref(this);
+ serial_in_file_option->init();
+ serial_in_file_option->use("serial_in_file");
+ serial_out_file_option= new cl_optref(this);
+ serial_out_file_option->init();
+ serial_out_file_option->use("serial_out_file");
+
+ //char *fni, *fno;
+ /*if ((fni= serial_in_file_option->get_value((char*)0)))
+ serial_in= fopen(fni, "r");
+ if ((fno= serial_out_file_option->get_value((char*)0)))
+ serial_out= fopen(fno, "w");*/
+
+ //serial_in = (FILE*)application->args->get_parg(0, "Ser_in");
+ //serial_out= (FILE*)application->args->get_parg(0, "Ser_out");
+ serial_in = (FILE*)serial_in_file_option->get_value((void*)0);
+ serial_out= (FILE*)serial_out_file_option->get_value((void*)0);
+
+ if (serial_in != serial_out && serial_in)
+ {
+ // making `serial' unbuffered
+ if (setvbuf(serial_in, NULL, _IONBF, 0))
+ perror("Unbuffer serial input channel");
+#ifdef _WIN32
+ if (CH_SERIAL != get_handle_type((HANDLE)_get_osfhandle(fileno(serial_in))))
+#elif defined HAVE_TERMIOS_H
+ // setting O_NONBLOCK
+ if ((i= fcntl(fileno(serial_in), F_GETFL, 0)) < 0)
+ perror("Get flags of serial input");
+ i|= O_NONBLOCK;
+ if (fcntl(fileno(serial_in), F_SETFL, i) < 0)
+ perror("Set flags of serial input");
+ // switching terminal to noncanonical mode
+ if (isatty(fileno(serial_in)))
+ {
+ tcgetattr(fileno(serial_in), &saved_attributes_in);
+ tcgetattr(fileno(serial_in), &tattr);
+ tattr.c_lflag&= ~(ICANON|ECHO);
+ tattr.c_cc[VMIN] = 1;
+ tattr.c_cc[VTIME]= 0;
+ tcsetattr(fileno(serial_in), TCSAFLUSH, &tattr);
+ }
+ else
+#endif
+ fprintf(stderr, "Warning: serial input interface connected to a "
+ "non-terminal file.\n");
+ }
+ if (serial_out)
+ {
+ // making `serial' unbuffered
+ if (setvbuf(serial_out, NULL, _IONBF, 0))
+ perror("Unbuffer serial output channel");
+#ifdef _WIN32
+ if (CH_SERIAL != get_handle_type((HANDLE)_get_osfhandle(fileno(serial_out))))
+#elif defined HAVE_TERMIOS_H
+ // setting O_NONBLOCK
+ if ((i= fcntl(fileno(serial_out), F_GETFL, 0)) < 0)
+ perror("Get flags of serial output");
+ i|= O_NONBLOCK;
+ if (fcntl(fileno(serial_out), F_SETFL, i) < 0)
+ perror("Set flags of serial output");
+ // switching terminal to noncanonical mode
+ if (isatty(fileno(serial_out)))
+ {
+ tcgetattr(fileno(serial_out), &saved_attributes_out);
+ tcgetattr(fileno(serial_out), &tattr);
+ tattr.c_lflag&= ~(ICANON|ECHO);
+ tattr.c_cc[VMIN] = 1;
+ tattr.c_cc[VTIME]= 0;
+ tcsetattr(fileno(serial_out), TCSAFLUSH, &tattr);
+ }
+ else
+#endif
+ fprintf(stderr, "Warning: serial output interface connected to a "
+ "non-terminal file.\n");
+ }
+
+ class cl_hw *t2= uc->get_hw(HW_TIMER, 2, 0);
+ if ((there_is_t2= t2 != 0))
+ {
+ t_mem d= sfr->get(T2CON);
+ t2_baud= d & (bmRCLK | bmTCLK);
+ }
+ else
+ t2_baud= DD_FALSE;
+
return(0);
+}
+
+void
+cl_serial::new_hw_added(class cl_hw *new_hw)
+{
+ if (new_hw->cathegory == HW_TIMER &&
+ new_hw->id == 2)
+ {
+ there_is_t2= DD_TRUE;
+ t_mem d= sfr->get(T2CON);
+ t2_baud= d & (bmRCLK | bmTCLK);
+ }
+}
+
+void
+cl_serial::added_to_uc(void)
+{
+ uc->it_sources->add(new cl_it_src(bmES , SCON, bmTI , 0x0023, false,
+ "serial transmit", 6));
+ uc->it_sources->add(new cl_it_src(bmES , SCON, bmRI , 0x0023, false,
+ "serial receive", 6));
+}
+
+t_mem
+cl_serial::read(class cl_memory_cell *cell)
+{
+ if (cell == sbuf)
+ return(s_in);
+ else
+ return(cell->get());
+}
+
+void
+cl_serial::write(class cl_memory_cell *cell, t_mem *val)
+{
+ if (cell == sbuf)
+ {
+ s_out= *val;
+ s_sending= DD_TRUE;
+ s_tr_bit = 0;
+ s_tr_tick= 0;
+ s_tr_t1= 0;
+ }
+ if (cell == scon)
+ {
+ _mode= *val >> 6;
+ _bmREN= *val & bmREN;
+ _bits= 8;
+ switch (_mode)
+ {
+ case 0:
+ _bits= 8;
+ _divby= 12;
+ break;
+ case 1:
+ _bits= 10;
+ _divby= _bmSMOD?16:32;
+ break;
+ case 2:
+ _bits= 11;
+ _divby= _bmSMOD?16:32;
+ break;
+ case 3:
+ _bits= 11;
+ _divby= _bmSMOD?16:32;
+ break;
+ }
+ }
+ else if (cell == pcon)
+ {
+ _bmSMOD= *val & bmSMOD;
+ /*switch (_mode)
+ {
+ case 1:
+ _divby= _bmSMOD?16:32;
+ break;
+ case 2:
+ _divby= _bmSMOD?16:32;
+ break;
+ case 3:
+ _divby= _bmSMOD?16:32;
+ break;
+ }*/
+ if (_mode)
+ _divby= _bmSMOD?16:32;
+ }
+}
+
+/*void
+cl_serial::mem_cell_changed(class cl_m *mem, t_addr addr)
+{
+ t_mem d;
+
+ d= sbuf->get();
+ write(sbuf, &d);
+ d= pcon->get();
+ write(pcon, &d);
+ d= scon->get();
+ write(scon, &d);
}*/
+int
+cl_serial::serial_bit_cnt(void)
+{
+ //int divby= 12;
+ int *tr_src= 0, *rec_src= 0;
+
+ switch (_mode)
+ {
+ case 0:
+ //divby = 12;
+ tr_src = &s_tr_tick;
+ rec_src= &s_rec_tick;
+ break;
+ case 1:
+ case 3:
+ //divby = (/*pcon->get()&bmSMOD*/_bmSMOD)?16:32;
+ tr_src = &s_tr_t1;
+ rec_src= &s_rec_t1;
+ break;
+ case 2:
+ //divby = (/*pcon->get()&bmSMOD*/_bmSMOD)?16:32;
+ tr_src = &s_tr_tick;
+ rec_src= &s_rec_tick;
+ break;
+ }
+ if (t2_baud)
+ _divby= 16;
+ if (s_sending)
+ {
+ while (*tr_src >= _divby)
+ {
+ (*tr_src)-= _divby;
+ s_tr_bit++;
+ //printf("serial bit sent %d\n",uc->ticks->ticks);
+ }
+ }
+ if (s_receiving)
+ {
+ while (*rec_src >= _divby)
+ {
+ (*rec_src)-= _divby;
+ s_rec_bit++;
+ }
+ }
+ return(0);
+}
+
+int
+cl_serial::tick(int cycles)
+{
+ char c;
+
+ serial_bit_cnt(/*_mode*/);
+ if (s_sending &&
+ (s_tr_bit >= _bits))
+ {
+ s_sending= DD_FALSE;
+ scon->set_bit1(bmTI);
+ if (serial_out)
+ {
+ putc(s_out, serial_out);
+ fflush(serial_out);
+ }
+ s_tr_bit-= _bits;
+ //printf("serial out %d bit rems %d\n",s_tr_bit,uc->ticks->ticks);
+ }
+ if ((/*scn & bmREN*/_bmREN) &&
+ serial_in &&
+ !s_receiving)
+ {
+#ifdef _WIN32
+ HANDLE handle = (HANDLE)_get_osfhandle(fileno(serial_in));
+ assert(INVALID_HANDLE_VALUE != handle);
+
+ if (input_avail(handle))
+#else
+ if (input_avail(fileno(serial_in)))
+#endif
+ {
+ s_receiving= DD_TRUE;
+ s_rec_bit= 0;
+ s_rec_tick= /*uc51->*/s_rec_t1= 0;
+ }
+ }
+ if (s_receiving &&
+ (s_rec_bit >= _bits))
+ {
+ if (::read(fileno(serial_in), &c, 1) == 1)
+ {
+ s_in= c;
+ sbuf->set(s_in);
+ received(c);
+ }
+ s_receiving= DD_FALSE;
+ s_rec_bit-= _bits;
+ }
+
+ int l;
+ s_tr_tick+= (l= cycles * uc->clock_per_cycle());
+ s_rec_tick+= l;
+ return(0);
+}
+
+void
+cl_serial::received(int c)
+{
+ scon->set_bit1(bmRI);
+}
+
+void
+cl_serial::reset(void)
+{
+ s_tr_t1 = 0;
+ s_rec_t1 = 0;
+ s_tr_tick = 0;
+ s_rec_tick = 0;
+ s_in = 0;
+ s_out = 0;
+ s_sending = DD_FALSE;
+ s_receiving= DD_FALSE;
+ s_rec_bit = 0;
+ s_tr_bit = 0;
+}
+
+void
+cl_serial::happen(class cl_hw *where, enum hw_event he, void *params)
+{
+ if (where->cathegory == HW_TIMER)
+ {
+ if (where->id == 1)
+ {
+ //printf("serial: timer overflowed %ld\n", uc->ticks->ticks);
+ s_rec_t1++;
+ s_tr_t1++;
+ }
+ if (where->id == 2 /*&& there_is_t2*/)
+ {
+ switch (he)
+ {
+ case EV_T2_MODE_CHANGED:
+ {
+ if (!t2_baud)
+ s_rec_t1= s_tr_t1= 0;
+ t_mem *d= (t_mem *)params;
+ t2_baud= *d & (bmRCLK | bmTCLK);
+ break;
+ }
+ case EV_OVERFLOW:
+ //printf("T2 \abaud ov r%d t%d\n",s_rec_t1,s_tr_t1);
+ s_rec_t1++;
+ s_tr_t1++;
+ break;
+ default: break;
+ }
+ }
+ }
+}
+
void
-cl_serial::print_info(class cl_console *con)
+cl_serial::print_info(class cl_console_base *con)
{
char *modes[]= { "Shift, fixed clock",
- "8 bit UART timer clocked",
- "9 bit UART fixed clock",
- "9 bit UART timer clocked" };
- int scon= uc->get_mem(MEM_SFR, SCON);
+ "8 bit UART timer clocked",
+ "9 bit UART fixed clock",
+ "9 bit UART timer clocked" };
+ int sc= scon->get();
con->dd_printf("%s[%d]", id_string, id);
- int mode= (scon&(bmSM0|bmSM1))>>6;
- con->dd_printf(" %s MultiProc=%s", modes[mode],
- (mode&2)?((scon&bmSM2)?"ON":"OFF"):"none");
- con->dd_printf(" irq=%s", (uc->get_mem(MEM_SFR, IE)&bmES)?"en":"dis");
+ int mode= (sc&(bmSM0|bmSM1))>>6;
+ con->dd_printf(" %s", modes[mode]);
+ if (mode == 1 || mode == 2)
+ con->dd_printf(" (timer%d)", (t2_baud)?2:1);
+ con->dd_printf(" MultiProc=%s",
+ (mode&2)?((sc&bmSM2)?"ON":"OFF"):"none");
+ con->dd_printf(" irq=%s", (sfr->get(IE)&bmES)?"en":"dis");
con->dd_printf(" prio=%d", uc->it_priority(bmPS));
con->dd_printf("\n");
con->dd_printf("Receiver");
- con->dd_printf(" %s", (scon&bmREN)?"ON":"OFF");
- con->dd_printf(" RB8=%c", (scon&bmRB8)?'1':'0');
- con->dd_printf(" irq=%c", (scon&bmRI)?'1':'0');
+ con->dd_printf(" %s", (sc&bmREN)?"ON":"OFF");
+ con->dd_printf(" RB8=%c", (sc&bmRB8)?'1':'0');
+ con->dd_printf(" irq=%c", (sc&bmRI)?'1':'0');
con->dd_printf("\n");
con->dd_printf("Transmitter");
- con->dd_printf(" TB8=%c", (scon&bmTB8)?'1':'0');
- con->dd_printf(" irq=%c", (scon&bmTI)?'1':'0');
+ con->dd_printf(" TB8=%c", (sc&bmTB8)?'1':'0');
+ con->dd_printf(" irq=%c", (sc&bmTI)?'1':'0');
con->dd_printf("\n");
+ /*con->dd_printf("s_rec_t1=%d s_rec_bit=%d s_rec_tick=%d\n",
+ s_rec_t1, s_rec_bit, s_rec_tick);
+ con->dd_printf("s_tr_t1=%d s_tr_bit=%d s_tr_tick=%d\n",
+ s_tr_t1, s_tr_bit, s_tr_tick);
+ con->dd_printf("divby=%d bits=%d\n", _divby, _bits);*/
}