/[gxemul]/trunk/src/devices/dev_mp.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_mp.c

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

revision 4 by dpavlin, Mon Oct 8 16:18:00 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_mp.c,v 1.25 2005/02/25 06:27:48 debug Exp $   *  $Id: dev_mp.c,v 1.42 2007/06/15 19:57:33 debug Exp $
29     *
30     *  COMMENT: Generic Multi-processor controller for the test machines
31   *   *
32   *  This is a fake multiprocessor (MP) device. It can be useful for   *  This is a fake multiprocessor (MP) device. It can be useful for
33   *  theoretical experiments, but probably bares no resemblance to any   *  theoretical experiments, but probably bares no resemblance to any
34   *  multiprocessor controller used in any real machine.   *  multiprocessor controller used in any real machine.
35     *
36     *  NOTE: The devinit irq string should be the part _after_ "cpu[%i].".
37     *        For MIPS, it will be MIPS_IPI_INT.
38   */   */
39    
40  #include <stdio.h>  #include <stdio.h>
# Line 37  Line 42 
42  #include <string.h>  #include <string.h>
43    
44  #include "cpu.h"  #include "cpu.h"
 #include "cpu_mips.h"  
45  #include "device.h"  #include "device.h"
46  #include "machine.h"  #include "machine.h"
47    #include "interrupt.h"
48  #include "memory.h"  #include "memory.h"
49  #include "misc.h"  #include "misc.h"
50  #include "mp.h"  
51    #include "testmachine/dev_mp.h"
52    
53    
54  struct mp_data {  struct mp_data {
# Line 50  struct mp_data { Line 56  struct mp_data {
56          uint64_t        startup_addr;          uint64_t        startup_addr;
57          uint64_t        stack_addr;          uint64_t        stack_addr;
58          uint64_t        pause_addr;          uint64_t        pause_addr;
59    
60            /*  Each CPU has an array of pending ipis.  */
61            int             *n_pending_ipis;
62            int             **ipi;
63    
64            /*  Connections to all CPUs' IPI pins:  */
65            struct interrupt *ipi_irq;
66  };  };
67    
68    
69  /*  extern int single_step;
70   *  dev_mp_access():  
71   */  
72  int dev_mp_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr,  DEVICE_ACCESS(mp)
         unsigned char *data, size_t len, int writeflag, void *extra)  
73  {  {
74          struct mp_data *d = extra;          struct mp_data *d = extra;
75          int i, which_cpu;          int i, which_cpu;
76          uint64_t idata = 0, odata = 0;          uint64_t idata = 0, odata = 0;
77    
78          idata = memory_readmax64(cpu, data, len);          if (writeflag == MEM_WRITE)
79                    idata = memory_readmax64(cpu, data, len);
80    
81          /*          /*
82           *  NOTE: It is up to the user of this device to read or write           *  NOTE: It is up to the user of this device to read or write
# Line 113  int dev_mp_access(struct cpu *cpu, struc Line 126  int dev_mp_access(struct cpu *cpu, struc
126                  break;                  break;
127    
128          case DEV_MP_PAUSE_CPU:          case DEV_MP_PAUSE_CPU:
129                  /*  Pause all cpus except our selves:  */                  /*  Pause all cpus except a specific CPU:  */
130                  which_cpu = idata;                  which_cpu = idata;
131    
132                  for (i=0; i<cpu->machine->ncpus; i++)                  for (i=0; i<cpu->machine->ncpus; i++)
133                          if (i!=which_cpu)                          if (i != which_cpu)
134                                  d->cpus[i]->running = 0;                                  d->cpus[i]->running = 0;
135                  break;                  break;
136    
137          case DEV_MP_UNPAUSE_CPU:          case DEV_MP_UNPAUSE_CPU:
138                  /*  Unpause all cpus except our selves:  */                  /*  Unpause a specific CPU:  */
139                  which_cpu = idata;                  which_cpu = idata;
140                  for (i=0; i<cpu->machine->ncpus; i++)  
141                          if (i!=which_cpu)                  if (which_cpu >= 0 && which_cpu <cpu->machine->ncpus)
142                                  d->cpus[i]->running = 1;                          d->cpus[which_cpu]->running = 1;
143                  break;                  break;
144    
145          case DEV_MP_STARTUPSTACK:          case DEV_MP_STARTUPSTACK:
# Line 136  int dev_mp_access(struct cpu *cpu, struc Line 149  int dev_mp_access(struct cpu *cpu, struc
149                  break;                  break;
150    
151          case DEV_MP_HARDWARE_RANDOM:          case DEV_MP_HARDWARE_RANDOM:
152                  /*  Return (up to) 64 bits of "hardware random":  */                  /*
153                     *  Return (up to) 64 bits of "hardware random":
154                     *
155                     *  NOTE: Remember that random() is (usually) 31 bits of
156                     *        random data, _NOT_ 32, hence this construction.
157                     */
158                  odata = random();                  odata = random();
159                  odata = (odata << 31) ^ random();                  odata = (odata << 31) ^ random();
160                  odata = (odata << 31) ^ random();                  odata = (odata << 31) ^ random();
# Line 153  int dev_mp_access(struct cpu *cpu, struc Line 171  int dev_mp_access(struct cpu *cpu, struc
171                  odata = cpu->machine->physical_ram_in_mb * 1048576;                  odata = cpu->machine->physical_ram_in_mb * 1048576;
172                  break;                  break;
173    
174            case DEV_MP_IPI_ONE:
175            case DEV_MP_IPI_MANY:
176                    /*
177                     *  idata should be of the form:
178                     *
179                     *              (IPI_nr << 16) | cpu_id
180                     *
181                     *  This will send an Inter-processor interrupt to a specific
182                     *  CPU. (DEV_MP_IPI_MANY sends to all _except_ the specific
183                     *  CPU.)
184                     *
185                     *  Sending an IPI means adding the IPI last in the list of
186                     *  pending IPIs, and asserting the IPI "pin".
187                     */
188                    which_cpu = (idata & 0xffff);
189                    for (i=0; i<cpu->machine->ncpus; i++) {
190                            int send_it = 0;
191                            if (relative_addr == DEV_MP_IPI_ONE && i == which_cpu)
192                                    send_it = 1;
193                            if (relative_addr == DEV_MP_IPI_MANY && i != which_cpu)
194                                    send_it = 1;
195                            if (send_it) {
196                                    d->n_pending_ipis[i] ++;
197                                    CHECK_ALLOCATION(d->ipi[i] = realloc(d->ipi[i],
198                                        d->n_pending_ipis[i] * sizeof(int)));
199    
200                                    /*  Add the IPI last in the array:  */
201                                    d->ipi[i][d->n_pending_ipis[i] - 1] =
202                                        idata >> 16;
203    
204                                    INTERRUPT_ASSERT(d->ipi_irq[i]);
205                            }
206                    }
207                    break;
208    
209            case DEV_MP_IPI_READ:
210                    /*
211                     *  If the current CPU has any IPIs pending, accessing this
212                     *  address reads the IPI value. (Writing to this address
213                     *  discards _all_ pending IPIs.)  If there is no pending
214                     *  IPI, then 0 is returned. Usage of the value 0 for real
215                     *  IPIs should thus be avoided.
216                     */
217                    if (writeflag == MEM_WRITE) {
218                            d->n_pending_ipis[cpu->cpu_id] = 0;
219                    }
220                    odata = 0;
221                    if (d->n_pending_ipis[cpu->cpu_id] > 0) {
222                            odata = d->ipi[cpu->cpu_id][0];
223                            if (d->n_pending_ipis[cpu->cpu_id]-- > 1)
224                                    memmove(&d->ipi[cpu->cpu_id][0],
225                                        &d->ipi[cpu->cpu_id][1],
226                                        d->n_pending_ipis[cpu->cpu_id]);
227                    }
228    
229                    /*  Deassert the interrupt, if there are no pending IPIs:  */
230                    if (d->n_pending_ipis[cpu->cpu_id] == 0)
231                            INTERRUPT_DEASSERT(d->ipi_irq[cpu->cpu_id]);
232                    break;
233    
234            case DEV_MP_NCYCLES:
235                    /*
236                     *  Return _approximately_ the number of cycles executed
237                     *  on this CPU.
238                     *
239                     *  (This value is not updated for each instruction.)
240                     */
241                    odata = cpu->ninstrs;
242                    break;
243    
244          default:          default:
245                  fatal("[ dev_mp: unimplemented relative addr 0x%x ]\n",                  fatal("[ dev_mp: unimplemented relative addr 0x%x ]\n",
246                      relative_addr);                      relative_addr);
# Line 165  int dev_mp_access(struct cpu *cpu, struc Line 253  int dev_mp_access(struct cpu *cpu, struc
253  }  }
254    
255    
256  /*  DEVINIT(mp)
  *  devinit_mp():  
  */  
 int devinit_mp(struct devinit *devinit)  
257  {  {
258          struct mp_data *d;          struct mp_data *d;
259          d = malloc(sizeof(struct mp_data));          int n, i;
260          if (d == NULL) {  
261                  fprintf(stderr, "out of memory\n");          CHECK_ALLOCATION(d = malloc(sizeof(struct mp_data)));
                 exit(1);  
         }  
262          memset(d, 0, sizeof(struct mp_data));          memset(d, 0, sizeof(struct mp_data));
263    
264          d->cpus = devinit->machine->cpus;          d->cpus = devinit->machine->cpus;
265          d->startup_addr = INITIAL_PC;          d->startup_addr = INITIAL_PC;
266          d->stack_addr = INITIAL_STACK_POINTER;          d->stack_addr = INITIAL_STACK_POINTER;
267    
268          memory_device_register(devinit->machine->memory,          n = devinit->machine->ncpus;
269              devinit->name, devinit->addr, DEV_MP_LENGTH,  
270              dev_mp_access, d, MEM_DEFAULT, NULL);          /*  Connect to all CPUs' IPI pins:  */
271            CHECK_ALLOCATION(d->ipi_irq = malloc(n * sizeof(struct interrupt)));
272    
273            for (i=0; i<n; i++) {
274                    char tmpstr[200];
275                    snprintf(tmpstr, sizeof(tmpstr), "%s.cpu[%i].%s",
276                        devinit->machine->path, i, devinit->interrupt_path);
277                    INTERRUPT_CONNECT(tmpstr, d->ipi_irq[i]);
278            }
279    
280            CHECK_ALLOCATION(d->n_pending_ipis = malloc(n * sizeof(int)));
281            memset(d->n_pending_ipis, 0, sizeof(int) * n);
282    
283            CHECK_ALLOCATION(d->ipi = malloc(n * sizeof(int *)));
284            memset(d->ipi, 0, sizeof(int *) * n);
285    
286            memory_device_register(devinit->machine->memory, devinit->name,
287                devinit->addr, DEV_MP_LENGTH, dev_mp_access, d, DM_DEFAULT, NULL);
288    
289          return 1;          return 1;
290  }  }

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

  ViewVC Help
Powered by ViewVC 1.1.26