/[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 14 by dpavlin, Mon Oct 8 16:18:51 2007 UTC revision 42 by dpavlin, Mon Oct 8 16:22:32 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2003-2005  Anders Gavare.  All rights reserved.   *  Copyright (C) 2003-2007  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.41 2005/09/30 13:33:01 debug Exp $   *  $Id: dev_ns16550.c,v 1.62 2007/06/15 19:57:33 debug Exp $
29   *     *  
30   *  NS16550 serial controller.   *  COMMENT: NS16550 serial controller
  *  
31   *   *
32   *  TODO: Implement the FIFO.   *  TODO: Implement the FIFO.
33   */   */
# Line 40  Line 39 
39  #include "console.h"  #include "console.h"
40  #include "cpu.h"  #include "cpu.h"
41  #include "device.h"  #include "device.h"
42    #include "interrupt.h"
43  #include "machine.h"  #include "machine.h"
44  #include "memory.h"  #include "memory.h"
45  #include "misc.h"  #include "misc.h"
# Line 55  Line 55 
55  struct ns_data {  struct ns_data {
56          int             addrmult;          int             addrmult;
57          int             in_use;          int             in_use;
         int             irqnr;  
58          char            *name;          char            *name;
59          int             console_handle;          int             console_handle;
60          int             enable_fifo;          int             enable_fifo;
61    
62            struct interrupt irq;
63    
64          unsigned char   reg[DEV_NS16550_LENGTH];          unsigned char   reg[DEV_NS16550_LENGTH];
65          unsigned char   fcr;            /*  FIFO control register  */          unsigned char   fcr;            /*  FIFO control register  */
66            int             int_asserted;
67          int             dlab;           /*  Divisor Latch Access bit  */          int             dlab;           /*  Divisor Latch Access bit  */
68          int             divisor;          int             divisor;
69    
# Line 72  struct ns_data { Line 73  struct ns_data {
73  };  };
74    
75    
76  /*  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)  
77  {  {
78            /*
79             *  This function is called at regular intervals. An interrupt is
80             *  asserted if there is a character available for reading, or if the
81             *  transmitter slot is empty (i.e. the ns16550 is ready to transmit).
82             */
83          struct ns_data *d = extra;          struct ns_data *d = extra;
84    
85          d->reg[com_iir] &= ~IIR_RXRDY;          d->reg[com_iir] &= ~IIR_RXRDY;
86          if (d->in_use && console_charavail(d->console_handle))          if (console_charavail(d->console_handle))
87                  d->reg[com_iir] |= IIR_RXRDY;                  d->reg[com_iir] |= IIR_RXRDY;
88    
89          /*          /*
90           *  If interrupts are enabled, and interrupts are pending, then           *  If interrupts are enabled, and interrupts are pending, then
91           *  cause a CPU interrupt.           *  cause a CPU interrupt.
92           */           */
93    
94          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)) ||
95              ((d->reg[com_ier] & IER_ERXRDY) && (d->reg[com_iir] & IIR_RXRDY))) {              ((d->reg[com_ier] & IER_ERXRDY) && (d->reg[com_iir] & IIR_RXRDY))) {
96                  d->reg[com_iir] &= ~IIR_NOPEND;                  d->reg[com_iir] &= ~IIR_NOPEND;
97                  if (d->reg[com_mcr] & MCR_IENABLE)                  if (d->reg[com_mcr] & MCR_IENABLE) {
98                          cpu_interrupt(cpu, d->irqnr);                          INTERRUPT_ASSERT(d->irq);
99                            d->int_asserted = 1;
100                    }
101          } else {          } else {
102                  d->reg[com_iir] |= IIR_NOPEND;                  d->reg[com_iir] |= IIR_NOPEND;
103                  cpu_interrupt_ack(cpu, d->irqnr);                  if (d->int_asserted)
104                            INTERRUPT_DEASSERT(d->irq);
105                    d->int_asserted = 0;
106          }          }
107  }  }
108    
109    
110  /*  DEVICE_ACCESS(ns16550)
  *  dev_ns16550_access():  
  */  
 int dev_ns16550_access(struct cpu *cpu, struct memory *mem,  
         uint64_t relative_addr, unsigned char *data, size_t len,  
         int writeflag, void *extra)  
111  {  {
112          uint64_t idata = 0, odata=0;          uint64_t idata = 0, odata=0;
113          int i;          size_t i;
114          struct ns_data *d = extra;          struct ns_data *d = extra;
115    
116          idata = memory_readmax64(cpu, data, len);          if (writeflag == MEM_WRITE)
117                    idata = memory_readmax64(cpu, data, len);
118    
119    #if 0
120          /*  The NS16550 should be accessed using byte read/writes:  */          /*  The NS16550 should be accessed using byte read/writes:  */
121          if (len != 1)          if (len != 1)
122                  fatal("[ ns16550 (%s): len=%i, idata=0x%16llx! ]\n",                  fatal("[ ns16550 (%s): len=%i, idata=0x%16llx! ]\n",
123                      d->name, len, (long long)idata);                      d->name, len, (long long)idata);
124    #endif
125    
126          /*          /*
127           *  Always ready to transmit:           *  Always ready to transmit:
# Line 132  int dev_ns16550_access(struct cpu *cpu, Line 134  int dev_ns16550_access(struct cpu *cpu,
134                  d->reg[com_iir] |= ((d->fcr << 5) & 0xc0);                  d->reg[com_iir] |= ((d->fcr << 5) & 0xc0);
135    
136          d->reg[com_lsr] &= ~LSR_RXRDY;          d->reg[com_lsr] &= ~LSR_RXRDY;
137          if (d->in_use && console_charavail(d->console_handle))          if (console_charavail(d->console_handle))
138                  d->reg[com_lsr] |= LSR_RXRDY;                  d->reg[com_lsr] |= LSR_RXRDY;
139    
140          relative_addr /= d->addrmult;          relative_addr /= d->addrmult;
# Line 165  int dev_ns16550_access(struct cpu *cpu, Line 167  int dev_ns16550_access(struct cpu *cpu,
167                                  console_putchar(d->console_handle, idata);                                  console_putchar(d->console_handle, idata);
168                          d->reg[com_iir] |= IIR_TXRDY;                          d->reg[com_iir] |= IIR_TXRDY;
169                  } else {                  } else {
170                          if (d->in_use)                          int x = console_readchar(d->console_handle);
171                                  odata = console_readchar(d->console_handle);                          odata = x < 0? 0 : x;
                         else  
                                 odata = 0;  
172                  }                  }
173                  dev_ns16550_tick(cpu, d);                  dev_ns16550_tick(cpu, d);
174                  break;                  break;
# Line 211  int dev_ns16550_access(struct cpu *cpu, Line 211  int dev_ns16550_access(struct cpu *cpu,
211                          d->fcr = idata;                          d->fcr = idata;
212                  } else {                  } else {
213                          odata = d->reg[com_iir];                          odata = d->reg[com_iir];
214                            if (d->reg[com_iir] & IIR_TXRDY)
215                                    d->reg[com_iir] &= ~IIR_TXRDY;
216                          debug("[ ns16550 (%s): read from iir: 0x%02x ]\n",                          debug("[ ns16550 (%s): read from iir: 0x%02x ]\n",
217                              d->name, (int)odata);                              d->name, (int)odata);
218                          dev_ns16550_tick(cpu, d);                          dev_ns16550_tick(cpu, d);
# Line 284  int dev_ns16550_access(struct cpu *cpu, Line 286  int dev_ns16550_access(struct cpu *cpu,
286                          d->reg[com_mcr] = idata;                          d->reg[com_mcr] = idata;
287                          debug("[ ns16550 (%s): write to mcr: 0x%02x ]\n",                          debug("[ ns16550 (%s): write to mcr: 0x%02x ]\n",
288                              d->name, (int)idata);                              d->name, (int)idata);
289                            if (!(d->reg[com_iir] & IIR_TXRDY)
290                                && (idata & MCR_IENABLE))
291                                    d->reg[com_iir] |= IIR_TXRDY;
292                            dev_ns16550_tick(cpu, d);
293                  } else {                  } else {
294                          odata = d->reg[com_mcr];                          odata = d->reg[com_mcr];
295                          debug("[ ns16550 (%s): read from mcr: 0x%02x ]\n",                          debug("[ ns16550 (%s): read from mcr: 0x%02x ]\n",
# Line 313  int dev_ns16550_access(struct cpu *cpu, Line 319  int dev_ns16550_access(struct cpu *cpu,
319  }  }
320    
321    
322  /*  DEVINIT(ns16550)
  *  devinit_ns16550():  
  */  
 int devinit_ns16550(struct devinit *devinit)  
323  {  {
324          struct ns_data *d = malloc(sizeof(struct ns_data));          struct ns_data *d;
325          size_t nlen;          size_t nlen;
326          char *name;          char *name;
327    
328          if (d == NULL) {          CHECK_ALLOCATION(d = malloc(sizeof(struct ns_data)));
                 fprintf(stderr, "out of memory\n");  
                 exit(1);  
         }  
329          memset(d, 0, sizeof(struct ns_data));          memset(d, 0, sizeof(struct ns_data));
330          d->irqnr        = devinit->irq_nr;  
331          d->addrmult     = devinit->addr_mult;          d->addrmult     = devinit->addr_mult;
332          d->in_use       = devinit->in_use;          d->in_use       = devinit->in_use;
333          d->enable_fifo  = 1;          d->enable_fifo  = 1;
# Line 338  int devinit_ns16550(struct devinit *devi Line 338  int devinit_ns16550(struct devinit *devi
338          d->stopbits     = "1";          d->stopbits     = "1";
339          d->name         = devinit->name2 != NULL? devinit->name2 : "";          d->name         = devinit->name2 != NULL? devinit->name2 : "";
340          d->console_handle =          d->console_handle =
341              console_start_slave(devinit->machine, devinit->name);              console_start_slave(devinit->machine, devinit->name2 != NULL?
342                devinit->name2 : devinit->name, d->in_use);
343    
344            INTERRUPT_CONNECT(devinit->interrupt_path, d->irq);
345    
346          nlen = strlen(devinit->name) + 10;          nlen = strlen(devinit->name) + 10;
347          if (devinit->name2 != NULL)          if (devinit->name2 != NULL)
348                  nlen += strlen(devinit->name2);                  nlen += strlen(devinit->name2);
349          name = malloc(nlen);          CHECK_ALLOCATION(name = malloc(nlen));
         if (name == NULL) {  
                 fprintf(stderr, "out of memory\n");  
                 exit(1);  
         }  
350          if (devinit->name2 != NULL && devinit->name2[0])          if (devinit->name2 != NULL && devinit->name2[0])
351                  snprintf(name, nlen, "%s [%s]", devinit->name, devinit->name2);                  snprintf(name, nlen, "%s [%s]", devinit->name, devinit->name2);
352          else          else
# Line 355  int devinit_ns16550(struct devinit *devi Line 354  int devinit_ns16550(struct devinit *devi
354    
355          memory_device_register(devinit->machine->memory, name, devinit->addr,          memory_device_register(devinit->machine->memory, name, devinit->addr,
356              DEV_NS16550_LENGTH * d->addrmult, dev_ns16550_access, d,              DEV_NS16550_LENGTH * d->addrmult, dev_ns16550_access, d,
357              MEM_DEFAULT, NULL);              DM_DEFAULT, NULL);
358          machine_add_tickfunction(devinit->machine,          machine_add_tickfunction(devinit->machine,
359              dev_ns16550_tick, d, TICK_SHIFT);              dev_ns16550_tick, d, TICK_SHIFT);
360    
361          /*          /*
362           *  NOTE:  Ugly cast into a pointer, because this is a convenient way           *  NOTE:  Ugly cast into a pointer, because this is a convenient way
363           *         to return the console handle to code in src/machine.c.           *         to return the console handle to code in src/machines/.
364           */           */
365          devinit->return_ptr = (void *)(size_t)d->console_handle;          devinit->return_ptr = (void *)(size_t)d->console_handle;
366    

Legend:
Removed from v.14  
changed lines
  Added in v.42

  ViewVC Help
Powered by ViewVC 1.1.26