/[gxemul]/trunk/src/devices/dev_ns16550.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /trunk/src/devices/dev_ns16550.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 18 by dpavlin, Mon Oct 8 16:19:11 2007 UTC revision 32 by dpavlin, Mon Oct 8 16:20:58 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2003-2005  Anders Gavare.  All rights reserved.   *  Copyright (C) 2003-2006  Anders Gavare.  All rights reserved.
3   *   *
4   *  Redistribution and use in source and binary forms, with or without   *  Redistribution and use in source and binary forms, with or without
5   *  modification, are permitted provided that the following conditions are met:   *  modification, are permitted provided that the following conditions are met:
# Line 25  Line 25 
25   *  SUCH DAMAGE.   *  SUCH DAMAGE.
26   *     *  
27   *   *
28   *  $Id: dev_ns16550.c,v 1.42 2005/10/26 14:37:04 debug Exp $   *  $Id: dev_ns16550.c,v 1.55 2006/10/27 13:12:21 debug Exp $
29   *     *  
30   *  NS16550 serial controller.   *  NS16550 serial controller.
31   *   *
# Line 62  struct ns_data { Line 62  struct ns_data {
62    
63          unsigned char   reg[DEV_NS16550_LENGTH];          unsigned char   reg[DEV_NS16550_LENGTH];
64          unsigned char   fcr;            /*  FIFO control register  */          unsigned char   fcr;            /*  FIFO control register  */
65            int             int_asserted;
66          int             dlab;           /*  Divisor Latch Access bit  */          int             dlab;           /*  Divisor Latch Access bit  */
67          int             divisor;          int             divisor;
68    
# Line 72  struct ns_data { Line 72  struct ns_data {
72  };  };
73    
74    
75  /*  DEVICE_TICK(ns16550)
  *  dev_ns16550_tick():  
  *  
  *  This function is called at regular intervals. An interrupt is caused to the  
  *  CPU if there is a character available for reading, or if the transmitter  
  *  slot is empty (i.e. the ns16550 is ready to transmit).  
  */  
 void dev_ns16550_tick(struct cpu *cpu, void *extra)  
76  {  {
77            /*
78             *  This function is called at regular intervals. An interrupt is
79             *  asserted if there is a character available for reading, or if the
80             *  transmitter slot is empty (i.e. the ns16550 is ready to transmit).
81             */
82          struct ns_data *d = extra;          struct ns_data *d = extra;
83    
84          d->reg[com_iir] &= ~IIR_RXRDY;          d->reg[com_iir] &= ~IIR_RXRDY;
85          if (d->in_use && console_charavail(d->console_handle))          if (console_charavail(d->console_handle))
86                  d->reg[com_iir] |= IIR_RXRDY;                  d->reg[com_iir] |= IIR_RXRDY;
87    
88          /*          /*
89           *  If interrupts are enabled, and interrupts are pending, then           *  If interrupts are enabled, and interrupts are pending, then
90           *  cause a CPU interrupt.           *  cause a CPU interrupt.
91           */           */
92    
93          if (((d->reg[com_ier] & IER_ETXRDY) && (d->reg[com_iir] & IIR_TXRDY)) ||          if (((d->reg[com_ier] & IER_ETXRDY) && (d->reg[com_iir] & IIR_TXRDY)) ||
94              ((d->reg[com_ier] & IER_ERXRDY) && (d->reg[com_iir] & IIR_RXRDY))) {              ((d->reg[com_ier] & IER_ERXRDY) && (d->reg[com_iir] & IIR_RXRDY))) {
95                  d->reg[com_iir] &= ~IIR_NOPEND;                  d->reg[com_iir] &= ~IIR_NOPEND;
96                  if (d->reg[com_mcr] & MCR_IENABLE)                  if (d->reg[com_mcr] & MCR_IENABLE) {
97                          cpu_interrupt(cpu, d->irqnr);                          cpu_interrupt(cpu, d->irqnr);
98                            d->int_asserted = 1;
99                    }
100          } else {          } else {
101                  d->reg[com_iir] |= IIR_NOPEND;                  d->reg[com_iir] |= IIR_NOPEND;
102                  cpu_interrupt_ack(cpu, d->irqnr);                  if (d->int_asserted)
103                            cpu_interrupt_ack(cpu, d->irqnr);
104                    d->int_asserted = 0;
105          }          }
106  }  }
107    
# Line 106  void dev_ns16550_tick(struct cpu *cpu, v Line 109  void dev_ns16550_tick(struct cpu *cpu, v
109  /*  /*
110   *  dev_ns16550_access():   *  dev_ns16550_access():
111   */   */
112  int dev_ns16550_access(struct cpu *cpu, struct memory *mem,  DEVICE_ACCESS(ns16550)
         uint64_t relative_addr, unsigned char *data, size_t len,  
         int writeflag, void *extra)  
113  {  {
114          uint64_t idata = 0, odata=0;          uint64_t idata = 0, odata=0;
115          int i;          size_t i;
116          struct ns_data *d = extra;          struct ns_data *d = extra;
117    
118          if (writeflag == MEM_WRITE)          if (writeflag == MEM_WRITE)
119                  idata = memory_readmax64(cpu, data, len);                  idata = memory_readmax64(cpu, data, len);
120    
121    #if 0
122          /*  The NS16550 should be accessed using byte read/writes:  */          /*  The NS16550 should be accessed using byte read/writes:  */
123          if (len != 1)          if (len != 1)
124                  fatal("[ ns16550 (%s): len=%i, idata=0x%16llx! ]\n",                  fatal("[ ns16550 (%s): len=%i, idata=0x%16llx! ]\n",
125                      d->name, len, (long long)idata);                      d->name, len, (long long)idata);
126    #endif
127    
128          /*          /*
129           *  Always ready to transmit:           *  Always ready to transmit:
# Line 133  int dev_ns16550_access(struct cpu *cpu, Line 136  int dev_ns16550_access(struct cpu *cpu,
136                  d->reg[com_iir] |= ((d->fcr << 5) & 0xc0);                  d->reg[com_iir] |= ((d->fcr << 5) & 0xc0);
137    
138          d->reg[com_lsr] &= ~LSR_RXRDY;          d->reg[com_lsr] &= ~LSR_RXRDY;
139          if (d->in_use && console_charavail(d->console_handle))          if (console_charavail(d->console_handle))
140                  d->reg[com_lsr] |= LSR_RXRDY;                  d->reg[com_lsr] |= LSR_RXRDY;
141    
142          relative_addr /= d->addrmult;          relative_addr /= d->addrmult;
# Line 166  int dev_ns16550_access(struct cpu *cpu, Line 169  int dev_ns16550_access(struct cpu *cpu,
169                                  console_putchar(d->console_handle, idata);                                  console_putchar(d->console_handle, idata);
170                          d->reg[com_iir] |= IIR_TXRDY;                          d->reg[com_iir] |= IIR_TXRDY;
171                  } else {                  } else {
172                          if (d->in_use)                          int x = console_readchar(d->console_handle);
173                                  odata = console_readchar(d->console_handle);                          odata = x < 0? 0 : x;
                         else  
                                 odata = 0;  
174                  }                  }
175                  dev_ns16550_tick(cpu, d);                  dev_ns16550_tick(cpu, d);
176                  break;                  break;
# Line 212  int dev_ns16550_access(struct cpu *cpu, Line 213  int dev_ns16550_access(struct cpu *cpu,
213                          d->fcr = idata;                          d->fcr = idata;
214                  } else {                  } else {
215                          odata = d->reg[com_iir];                          odata = d->reg[com_iir];
216                            if (d->reg[com_iir] & IIR_TXRDY)
217                                    d->reg[com_iir] &= ~IIR_TXRDY;
218                          debug("[ ns16550 (%s): read from iir: 0x%02x ]\n",                          debug("[ ns16550 (%s): read from iir: 0x%02x ]\n",
219                              d->name, (int)odata);                              d->name, (int)odata);
220                          dev_ns16550_tick(cpu, d);                          dev_ns16550_tick(cpu, d);
# Line 285  int dev_ns16550_access(struct cpu *cpu, Line 288  int dev_ns16550_access(struct cpu *cpu,
288                          d->reg[com_mcr] = idata;                          d->reg[com_mcr] = idata;
289                          debug("[ ns16550 (%s): write to mcr: 0x%02x ]\n",                          debug("[ ns16550 (%s): write to mcr: 0x%02x ]\n",
290                              d->name, (int)idata);                              d->name, (int)idata);
291                            if (!(d->reg[com_iir] & IIR_TXRDY)
292                                && (idata & MCR_IENABLE))
293                                    d->reg[com_iir] |= IIR_TXRDY;
294                            dev_ns16550_tick(cpu, d);
295                  } else {                  } else {
296                          odata = d->reg[com_mcr];                          odata = d->reg[com_mcr];
297                          debug("[ ns16550 (%s): read from mcr: 0x%02x ]\n",                          debug("[ ns16550 (%s): read from mcr: 0x%02x ]\n",
# Line 314  int dev_ns16550_access(struct cpu *cpu, Line 321  int dev_ns16550_access(struct cpu *cpu,
321  }  }
322    
323    
324  /*  DEVINIT(ns16550)
  *  devinit_ns16550():  
  */  
 int devinit_ns16550(struct devinit *devinit)  
325  {  {
326          struct ns_data *d = malloc(sizeof(struct ns_data));          struct ns_data *d = malloc(sizeof(struct ns_data));
327          size_t nlen;          size_t nlen;
# Line 339  int devinit_ns16550(struct devinit *devi Line 343  int devinit_ns16550(struct devinit *devi
343          d->stopbits     = "1";          d->stopbits     = "1";
344          d->name         = devinit->name2 != NULL? devinit->name2 : "";          d->name         = devinit->name2 != NULL? devinit->name2 : "";
345          d->console_handle =          d->console_handle =
346              console_start_slave(devinit->machine, devinit->name);              console_start_slave(devinit->machine, devinit->name2 != NULL?
347                devinit->name2 : devinit->name, d->in_use);
348    
349          nlen = strlen(devinit->name) + 10;          nlen = strlen(devinit->name) + 10;
350          if (devinit->name2 != NULL)          if (devinit->name2 != NULL)
# Line 356  int devinit_ns16550(struct devinit *devi Line 361  int devinit_ns16550(struct devinit *devi
361    
362          memory_device_register(devinit->machine->memory, name, devinit->addr,          memory_device_register(devinit->machine->memory, name, devinit->addr,
363              DEV_NS16550_LENGTH * d->addrmult, dev_ns16550_access, d,              DEV_NS16550_LENGTH * d->addrmult, dev_ns16550_access, d,
364              MEM_DEFAULT, NULL);              DM_DEFAULT, NULL);
365          machine_add_tickfunction(devinit->machine,          machine_add_tickfunction(devinit->machine,
366              dev_ns16550_tick, d, TICK_SHIFT);              dev_ns16550_tick, d, TICK_SHIFT, 0.0);
367    
368          /*          /*
369           *  NOTE:  Ugly cast into a pointer, because this is a convenient way           *  NOTE:  Ugly cast into a pointer, because this is a convenient way

Legend:
Removed from v.18  
changed lines
  Added in v.32

  ViewVC Help
Powered by ViewVC 1.1.26