/[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 28 by dpavlin, Mon Oct 8 16:20:26 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_mp.c,v 1.25 2005/02/25 06:27:48 debug Exp $   *  $Id: dev_mp.c,v 1.37 2006/07/01 21:15:46 debug Exp $
29   *   *
30   *  This is a fake multiprocessor (MP) device. It can be useful for   *  This is a fake multiprocessor (MP) device. It can be useful for
31   *  theoretical experiments, but probably bares no resemblance to any   *  theoretical experiments, but probably bares no resemblance to any
# Line 42  Line 42 
42  #include "machine.h"  #include "machine.h"
43  #include "memory.h"  #include "memory.h"
44  #include "misc.h"  #include "misc.h"
45  #include "mp.h"  
46    #include "testmachine/dev_mp.h"
47    
48    
49  struct mp_data {  struct mp_data {
# Line 50  struct mp_data { Line 51  struct mp_data {
51          uint64_t        startup_addr;          uint64_t        startup_addr;
52          uint64_t        stack_addr;          uint64_t        stack_addr;
53          uint64_t        pause_addr;          uint64_t        pause_addr;
54    
55            /*  Each CPU has an array of pending ipis.  */
56            int             *n_pending_ipis;
57            int             **ipi;
58  };  };
59    
60    
61    extern int single_step;
62    
63    
64  /*  /*
65   *  dev_mp_access():   *  dev_mp_access():
66   */   */
67  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)  
68  {  {
69          struct mp_data *d = extra;          struct mp_data *d = extra;
70          int i, which_cpu;          int i, which_cpu;
71          uint64_t idata = 0, odata = 0;          uint64_t idata = 0, odata = 0;
72    
73          idata = memory_readmax64(cpu, data, len);          if (writeflag == MEM_WRITE)
74                    idata = memory_readmax64(cpu, data, len);
75    
76          /*          /*
77           *  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 121  int dev_mp_access(struct cpu *cpu, struc
121                  break;                  break;
122    
123          case DEV_MP_PAUSE_CPU:          case DEV_MP_PAUSE_CPU:
124                  /*  Pause all cpus except our selves:  */                  /*  Pause all cpus except a specific CPU:  */
125                  which_cpu = idata;                  which_cpu = idata;
126    
127                  for (i=0; i<cpu->machine->ncpus; i++)                  for (i=0; i<cpu->machine->ncpus; i++)
128                          if (i!=which_cpu)                          if (i != which_cpu)
129                                  d->cpus[i]->running = 0;                                  d->cpus[i]->running = 0;
130                  break;                  break;
131    
132          case DEV_MP_UNPAUSE_CPU:          case DEV_MP_UNPAUSE_CPU:
133                  /*  Unpause all cpus except our selves:  */                  /*  Unpause a specific CPU:  */
134                  which_cpu = idata;                  which_cpu = idata;
135                  for (i=0; i<cpu->machine->ncpus; i++)  
136                          if (i!=which_cpu)                  if (which_cpu >= 0 && which_cpu <cpu->machine->ncpus)
137                                  d->cpus[i]->running = 1;                          d->cpus[which_cpu]->running = 1;
138                  break;                  break;
139    
140          case DEV_MP_STARTUPSTACK:          case DEV_MP_STARTUPSTACK:
# Line 136  int dev_mp_access(struct cpu *cpu, struc Line 144  int dev_mp_access(struct cpu *cpu, struc
144                  break;                  break;
145    
146          case DEV_MP_HARDWARE_RANDOM:          case DEV_MP_HARDWARE_RANDOM:
147                  /*  Return (up to) 64 bits of "hardware random":  */                  /*
148                     *  Return (up to) 64 bits of "hardware random":
149                     *
150                     *  NOTE: Remember that random() is (usually) 31 bits of
151                     *        random data, _NOT_ 32, hence this construction.
152                     */
153                  odata = random();                  odata = random();
154                  odata = (odata << 31) ^ random();                  odata = (odata << 31) ^ random();
155                  odata = (odata << 31) ^ random();                  odata = (odata << 31) ^ random();
# Line 153  int dev_mp_access(struct cpu *cpu, struc Line 166  int dev_mp_access(struct cpu *cpu, struc
166                  odata = cpu->machine->physical_ram_in_mb * 1048576;                  odata = cpu->machine->physical_ram_in_mb * 1048576;
167                  break;                  break;
168    
169            case DEV_MP_IPI_ONE:
170            case DEV_MP_IPI_MANY:
171                    /*
172                     *  idata should be of the form:
173                     *
174                     *              (IPI_nr << 16) | cpu_id
175                     *
176                     *  This will send an Inter-processor interrupt to a specific
177                     *  CPU. (DEV_MP_IPI_MANY sends to all _except_ the specific
178                     *  CPU.)
179                     *
180                     *  Sending an IPI means adding the IPI last in the list of
181                     *  pending IPIs, and asserting the IPI "pin".
182                     */
183                    which_cpu = (idata & 0xffff);
184                    for (i=0; i<cpu->machine->ncpus; i++) {
185                            int send_it = 0;
186                            if (relative_addr == DEV_MP_IPI_ONE && i == which_cpu)
187                                    send_it = 1;
188                            if (relative_addr == DEV_MP_IPI_MANY && i != which_cpu)
189                                    send_it = 1;
190                            if (send_it) {
191                                    d->n_pending_ipis[i] ++;
192                                    d->ipi[i] = realloc(d->ipi[i],
193                                        d->n_pending_ipis[i] * sizeof(int));
194                                    if (d->ipi[i] == NULL) {
195                                            fprintf(stderr, "out of memory\n");
196                                            exit(1);
197                                    }
198                                    /*  Add the IPI last in the array:  */
199                                    d->ipi[i][d->n_pending_ipis[i] - 1] =
200                                        idata >> 16;
201                                    cpu_interrupt(d->cpus[i], MIPS_IPI_INT);
202                            }
203                    }
204                    break;
205    
206            case DEV_MP_IPI_READ:
207                    /*
208                     *  If the current CPU has any IPIs pending, accessing this
209                     *  address reads the IPI value. (Writing to this address
210                     *  discards _all_ pending IPIs.)  If there is no pending
211                     *  IPI, then 0 is returned. Usage of the value 0 for real
212                     *  IPIs should thus be avoided.
213                     */
214                    if (writeflag == MEM_WRITE) {
215                            d->n_pending_ipis[cpu->cpu_id] = 0;
216                    }
217                    odata = 0;
218                    if (d->n_pending_ipis[cpu->cpu_id] > 0) {
219                            odata = d->ipi[cpu->cpu_id][0];
220                            if (d->n_pending_ipis[cpu->cpu_id]-- > 1)
221                                    memmove(&d->ipi[cpu->cpu_id][0],
222                                        &d->ipi[cpu->cpu_id][1],
223                                        d->n_pending_ipis[cpu->cpu_id]);
224                    }
225                    /*  Deassert the interrupt, if there are no pending IPIs:  */
226                    if (d->n_pending_ipis[cpu->cpu_id] == 0)
227                            cpu_interrupt_ack(d->cpus[cpu->cpu_id], MIPS_IPI_INT);
228                    break;
229    
230            case DEV_MP_NCYCLES:
231                    /*
232                     *  Return _approximately_ the number of cycles executed
233                     *  in this machine.
234                     *
235                     *  Note: At the moment, this is actually the number of
236                     *  instructions executed on CPU 0.
237                     *
238                     *  (This value is not updated for each instruction.)
239                     */
240                    odata = cpu->machine->ninstrs;
241                    break;
242    
243          default:          default:
244                  fatal("[ dev_mp: unimplemented relative addr 0x%x ]\n",                  fatal("[ dev_mp: unimplemented relative addr 0x%x ]\n",
245                      relative_addr);                      relative_addr);
# Line 165  int dev_mp_access(struct cpu *cpu, struc Line 252  int dev_mp_access(struct cpu *cpu, struc
252  }  }
253    
254    
255  /*  DEVINIT(mp)
  *  devinit_mp():  
  */  
 int devinit_mp(struct devinit *devinit)  
256  {  {
257          struct mp_data *d;          struct mp_data *d;
258            int n;
259    
260          d = malloc(sizeof(struct mp_data));          d = malloc(sizeof(struct mp_data));
261          if (d == NULL) {          if (d == NULL) {
262                  fprintf(stderr, "out of memory\n");                  fprintf(stderr, "out of memory\n");
# Line 181  int devinit_mp(struct devinit *devinit) Line 267  int devinit_mp(struct devinit *devinit)
267          d->startup_addr = INITIAL_PC;          d->startup_addr = INITIAL_PC;
268          d->stack_addr = INITIAL_STACK_POINTER;          d->stack_addr = INITIAL_STACK_POINTER;
269    
270          memory_device_register(devinit->machine->memory,          n = devinit->machine->ncpus;
271              devinit->name, devinit->addr, DEV_MP_LENGTH,          d->n_pending_ipis = malloc(n * sizeof(int));
272              dev_mp_access, d, MEM_DEFAULT, NULL);          d->ipi = malloc(n * sizeof(int *));
273            if (d->ipi == NULL || d->n_pending_ipis == NULL) {
274                    fprintf(stderr, "out of memory\n");
275                    exit(1);
276            }
277            memset(d->n_pending_ipis, 0, sizeof(int) * n);
278            memset(d->ipi, 0, sizeof(int *) * n);
279    
280            memory_device_register(devinit->machine->memory, devinit->name,
281                devinit->addr, DEV_MP_LENGTH, dev_mp_access, d, DM_DEFAULT, NULL);
282    
283          return 1;          return 1;
284  }  }

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

  ViewVC Help
Powered by ViewVC 1.1.26