OpenCores
URL https://opencores.org/ocsvn/igor/igor/trunk

Subversion Repositories igor

[/] [igor/] [trunk/] [avr/] [src/] [dispatch.c] - Blame information for rev 4

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 4 atypic
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include "global.h"
4
 
5
#include <stdint.h>
6
#include <stdlib.h>
7
#include <stdio.h>
8
#include <string.h>
9
 
10
#include "encdec.h"
11
#include "req.h"
12
#include "device.h"
13
#include "dispatch.h"
14
#include "dev/7seg.h"
15
#include "dev/spi.h"
16
 
17
#if ETHERNET_ENABLED
18
#define BUF ((struct uip_eth_hdr *)&uip_buf[0])
19
#include "uip/uip.h"
20
#include "uip/uip_arp.h"
21
#include "uip/timer.h"
22
#include "enc28j60-uip.c"
23
#endif
24
 
25
#include "req.h"
26
#include "bus.h"
27
 
28
/* Peripherals we know of. */
29
extern struct igordev igordev_boot;
30
extern struct igordev igordev_usart;
31
extern struct igordev igordev_mmc;
32
extern struct igordev igordev_kvga;
33
#ifdef ETHERNET_ENABLED
34
extern struct igordev igordev_telnet;
35
#define NUMDEV  5
36
#else
37
#define NUMDEV 4
38
#endif
39
struct igordev *idevs[NUMDEV];
40
 
41
// Currently seleted device
42
volatile uint32_t curdev;
43
// Last device performing interrupt.
44
volatile uint32_t intrdev;
45
 
46
volatile struct rqueue r_queue;
47
 
48
static void     dispatch_request_perform(struct req *);
49
 
50
#if ETHERNET_ENABLED
51
void init_network_stuff(void);
52
req_fn_t do_network_stuff;
53
#endif
54
 
55
#ifdef WITH_DEBUG
56
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
57
#else
58
#define DEBUG(...)
59
#endif
60
 
61
#if 0
62
void init_sram(void) __attribute__ ((naked)) __attribute__ ((section (".init3")));
63
 
64
void
65
init_sram(void)
66
{
67
        DDRC = 0xFF;
68
        PORTC = 0x00;
69
        XMCRA = (1 << SRE) | (1 << SRW11) | (1 << SRW10);
70
        XMCRB = 0x00;
71
}
72
#endif
73
 
74
/* Contains the dispatcher and its routines. */
75
int
76
main(void)
77
{
78
        struct idev_mgmt *imgmt;
79
        struct req *req;
80
        struct rqueue *rq;
81
        uint32_t i, data;
82
 
83
        cli();
84
        DDRC = 0xFF;
85
        PORTC = 0x00;
86
        XMCRA = (1 << SRE) | (1 << SRW11) | (1 << SRW10);
87
        XMCRB = 0x00;
88
 
89
        curdev = DEVTYPE_BOOT;
90
 
91
        display_init(); // 7Seg init
92
 
93
        /* Initialize device structure with the different device types. */
94
        idevs[DEVTYPE_BOOT] = &igordev_boot;
95
        idevs[DEVTYPE_SERIAL] = &igordev_usart;
96
        idevs[DEVTYPE_STORAGE] = &igordev_mmc;
97
        idevs[DEVTYPE_TERM] = &igordev_kvga;
98
#ifdef ETHERNET_ENABLED
99
        idevs[DEVTYPE_TELNET] = &igordev_telnet;
100
#endif
101
        rq = (struct rqueue *)&r_queue;
102
        rqueue_init(rq);
103
 
104
        init_fpgabus();
105
        _delay_ms(1);
106
        //display_init(); // 7Seg init
107
        DEBUG("Initializing devices\n");
108
        configure_spi(); //Must run before Ethernet/MMC init
109
        for (i = 0; i < NUMDEV; i++) {
110
                idevs[i]->init();
111
                imgmt = &idevs[i]->imgmt;
112
                imgmt->irqenable = 0;
113
                imgmt->baseaddr = 0;
114
                imgmt->curaddr = 0;
115
                imgmt->size = 0;
116
        }
117
#if ETHERNET_ENABLED
118
         //This also activates global interrupts as a side-effect
119
        init_network_stuff();
120
#endif
121
        DEBUG("Done initializing devices\n");
122
 
123
        /* Boot load test. */
124
        for (i = 0; i < 10; i++) {
125
                display_char(i);
126
                _delay_ms(50.0);
127
        }
128
        display_char(curdev);
129
/*
130
   BOOT BLOCK LAYOUT
131
 
132
   +---------------------------+----------+
133
   | Boot program size         | 4 bytes  |
134
   +---------------------------+----------+
135
   | Data area size            | 4 bytes  |
136
   +---------------------------+----------+
137
   |                           |          |
138
   |  Boot program             | Variable |
139
   |                           |          |
140
   +---------------------------+----------+
141
   |                           |          |
142
   |  Data area                | Variable |
143
   |                           |          |
144
   +---------------------------+----------+
145
 
146
 */
147
        /* Initialize the device boot block layout. */
148
        /* Read boot program size */
149
        igordev_mmc.read(0, (uint8_t *)&data, 4);
150
        igordev_boot.imgmt.size = swap32(data);
151
        igordev_mmc.read(0, (uint8_t *)&data, 4);
152
        igordev_mmc.imgmt.size = swap32(data);
153
        /* Set up segments. */
154
        igordev_boot.imgmt.baseaddr = 8;
155
        igordev_mmc.imgmt.baseaddr = 8 + igordev_boot.imgmt.size;
156
        _delay_ms(10);
157
        sei();
158
        avr_online();
159
 
160
#if ETHERNET_ENABLED
161
        //Do periodic polling of network interface
162
        //and housekeeping of TCP/IP stuff
163
        do_network_stuff(NULL);
164
#endif
165
        while (1) {
166
                /* Look through queue to see if we have anything. */
167
                while (!RQUEUE_EMPTY(rq)) {
168
                        req = req_peak(rq);
169
                        // Was empty
170
                        if (req == NULL)
171
                                break;
172
                        dispatch_request_perform(req);
173
                        req_free(rq);
174
                }
175
 
176
        }
177
        return (0);
178
}
179
 
180
static void
181
dispatch_request_perform(struct req *req)
182
{
183
        struct igordev *idev;
184
        struct idev_mgmt *imgmt;
185
        //char output[128];
186
        uint32_t data, d;
187
        uint8_t num, osize, total, *ptr;
188
 
189
        idev = req->dev;
190
        imgmt = &idev->imgmt;
191
        switch (req->type) {
192
        case REQ_TYPE_READ:
193
                /* Wait until device is ready. */
194
                while (idev->read_status != IDEV_STATUS_OK);
195
                total = DATA_SIZE_TYPE(DATA_TYPE_DEV(req->devnum));
196
                ptr = (uint8_t *)&data;
197
                while (idev->read_status != IDEV_STATUS_ERROR) {
198
                        cli();
199
                        num = idev->read(imgmt->curaddr + imgmt->baseaddr, ptr,
200
                            total);
201
                        sei();
202
                        /* If we were not able to read anything, postpone the
203
                         * request. */
204
                        if (num == 0) {
205
                                dispatch_request_make(idev, req->type,
206
                                    req->flags, req->devnum, NULL);
207
                                return;
208
                        }
209
                        total -= num;
210
                        imgmt->curaddr += num;
211
                        if (total <= 0)
212
                                break;
213
                        ptr += num;
214
                }
215
                if (idev->read_status == IDEV_STATUS_ERROR)
216
                        return;
217
                if (req->flags & REQ_CALLBACK) {
218
                        d = encode_object(data, req->devnum);
219
                        DEBUG("Perform buffer read from main: '%c'\n", d);
220
                        fpga_finish_read(d);
221
                }
222
                break;
223
        case REQ_TYPE_WRITE:
224
                /* Wait until device is ready. */
225
                while (idev->write_status != IDEV_STATUS_OK);
226
 
227
                data = decode_object(fpga_delayed_write(), req->devnum, &osize);
228
                total = osize;
229
//              if (imgmt->curaddr + total >= imgmt->size)
230
//                      imgmt->curaddr = 0;
231
                /* Write until we have been able to write the data. */
232
                /*if (req->devnum == DEVTYPE_STORAGE) {
233
                        snprintf(output, sizeof(output), "SD: c: %lld b: %lld"
234
                            " d:'%lx'\n", imgmt->curaddr, imgmt->baseaddr, data);
235
                        igordev_usart.write(0, output, strlen(output));
236
                        igordev_usart.flush();
237
                }*/
238
                ptr = (uint8_t *)&data;
239
                while (idev->write_status != IDEV_STATUS_ERROR) {
240
                        num = idev->write(imgmt->curaddr + imgmt->baseaddr, ptr,
241
                            osize);
242
                        // Try and flush if we can't write
243
                        // XXX: Should count and report error if it doesn't
244
                        // help.
245
                        if (num == 0)
246
                                idev->flush();
247
                        total -= num;
248
                        imgmt->curaddr += num;
249
                        if (total <= 0)
250
                                break;
251
                        ptr += num;
252
                }
253
                if (idev->write_status == IDEV_STATUS_ERROR)
254
                        return;
255
                // Request a flush now that we finished the write. We don't
256
                // check return value, but not much we can do really.
257
                idev->flush();
258
//              dispatch_request_make(idev, REQ_TYPE_FLUSH, 0, req->devnum, NULL);
259
                break;
260
        case REQ_TYPE_FLUSH:
261
                idev->flush();
262
                break;
263
        case REQ_TYPE_FUNC:
264
                req->func(idev->priv);
265
                break;
266
        }
267
}
268
 
269
/*
270
 * Make a request for the dispatcher.
271
 */
272
int8_t
273
dispatch_request_make(struct igordev *dev, uint8_t type, uint8_t flags,
274
    uint32_t devnum, req_fn_t *func)
275
{
276
        return (req_alloc((struct rqueue *)&r_queue, dev, type, flags, devnum, func));
277
}
278
 
279
int8_t
280
dispatch_request_read(uint8_t addr, uint32_t *data)
281
{
282
        struct igordev *idev;
283
        struct idev_mgmt *imgmt;
284
        uint32_t status;
285
 
286
        /* See what address we want to read from. */
287
        switch (addr) {
288
        case DEVICES:
289
                *data = OBJECT_NEW(TYPE_INT, NUMDEV);
290
                return (0);
291
        case CURDEV:
292
                *data = OBJECT_NEW(TYPE_INT, curdev);
293
                return (0);
294
        case CLI:
295
        case SAI:
296
                *data = 0;
297
                return (0);
298
        case INTRDEV:
299
                *data = OBJECT_NEW(TYPE_INT, intrdev);
300
                return (0);
301
        };
302
 
303
        /* Device-specific operation, so fetch currently enabled device. */
304
        idev = idevs[curdev];
305
        imgmt = &idev->imgmt;
306
 
307
        switch (addr) {
308
        /* Read an object from current device. */
309
        case OBJECT:
310
                /* Request for a read. */
311
                if (dispatch_request_make(idev, REQ_TYPE_READ, REQ_CALLBACK,
312
                    curdev, NULL) != 0)
313
                        return (-2); /* XXX: Set error. */
314
                return (-1); /* Tell FPGA to wait. */
315
        /* Read lower 26 bits of current address from device. */
316
        case ADDR_L:
317
                *data = OBJECT_NEW(TYPE_INT,
318
                    ((uint32_t)(imgmt->curaddr >> 2)));
319
                return (0);
320
        /* Read upper 26 bits of current address from device. */
321
        case ADDR_H:
322
                *data = OBJECT_NEW(TYPE_INT,
323
                    ((uint32_t)((imgmt->curaddr >> 2) >> SIZE_INT)));
324
                return (0);
325
        /* Read lower 26 bits of device size. */
326
        case SIZE_L:
327
                *data = OBJECT_NEW(TYPE_INT,
328
                    ((uint32_t)(imgmt->size >> 2)));
329
                return (0);
330
        /* Read upper 26 bits of device size. */
331
        case SIZE_H:
332
                *data = OBJECT_NEW(TYPE_INT,
333
                    ((uint32_t)((imgmt->size >> 2) >> SIZE_INT)));
334
                return (0);
335
        /* Read status register of device. */
336
        case STATUS:
337
                status = (idev->read_status == IDEV_STATUS_OK);
338
                status |= ((idev->write_status == IDEV_STATUS_OK) <<
339
                    1);
340
                /* XXX: Error codes. */
341
                *data = OBJECT_NEW(TYPE_INT, status);
342
                return (0);
343
        /* Device identification. */
344
        case IDENTIFICATION:
345
                *data = OBJECT_NEW(TYPE_INT, idev->id);
346
                return (0);
347
        /* Read irq enable for device. */
348
        case IRQENABLE:
349
                *data = OBJECT_NEW(TYPE_INT,
350
                    ((uint32_t)imgmt->irqenable));
351
                return (0);
352
        }
353
        return (0); /* Invalid request. */
354
}
355
 
356
int8_t
357
dispatch_request_write(uint8_t addr, uint32_t data)
358
{
359
        struct igordev *idev;
360
        struct idev_mgmt *imgmt;
361
        uint32_t status;
362
        uint64_t newaddr;
363
        uint8_t i; //num, osize;
364
 
365
        /* See what address we want to read from. */
366
        switch (addr) {
367
        /* Read-only */
368
        case DEVICES:
369
        case INTRDEV:
370
                return (0);
371
        case CURDEV:
372
                DEBUG("Setting current device\n");
373
                /* Should perhaps have some error signalling. */
374
                if (OBJECT_DATUM(data) >= NUMDEV)
375
                        return (0); /* Invalid device. */
376
                curdev = OBJECT_DATUM(data);
377
                display_char(curdev);
378
                return (0);
379
        case CLI:
380
                for (i = 0; i < NUMDEV; i++)
381
                        idevs[i]->imgmt.irqenable = 0;
382
                return (0);
383
        case SAI:
384
                for (i = 0; i < NUMDEV; i++)
385
                        idevs[i]->imgmt.irqenable = 1;
386
                return (0);
387
        };
388
        idev = idevs[curdev];
389
        imgmt = &idev->imgmt;
390
        switch (addr) {
391
        /* Read-only. */
392
        case SIZE_L:
393
        case SIZE_H:
394
        case IDENTIFICATION:
395
                return (0);
396
        /* Write an object from current device. */
397
        case OBJECT:
398
                if (dispatch_request_make(idev, REQ_TYPE_WRITE, REQ_CALLBACK,
399
                    curdev, NULL) != 0)
400
                        return (-2); /* XXX: panic. */
401
                return (-1);
402
        /* Write lower 26 bits of current address from device. */
403
        case ADDR_L:
404
                newaddr = (OBJECT_DATUM(data) << 2) |
405
                    ((uint64_t)((uint32_t)(imgmt->curaddr >> BSIZE_INT)) <<
406
                    BSIZE_INT);
407
                // Only set it if it does not exceed the device space.
408
                if (newaddr < imgmt->size)
409
                        imgmt->curaddr = newaddr;
410
                return (0);
411
        /* Read upper 26 bits of current address from device. */
412
        case ADDR_H:
413
                newaddr = ((OBJECT_DATUM(data) << 2) << BSIZE_INT) |
414
                    ((uint32_t)imgmt->curaddr);
415
                // Only set it if it does not exceed the device space.
416
                if (newaddr < imgmt->size)
417
                        imgmt->curaddr = newaddr;
418
                return (0);
419
        /* Read status register of device. */
420
        case STATUS:
421
                /* Writing 0 resets the error codes. */
422
                status = OBJECT_DATUM(data);
423
                if (status != 0)
424
                        return (0); /* Not allowed. */
425
                /* XXX: reset error codes. */
426
                return (0);
427
        /* Set irq enable for device. */
428
        case IRQENABLE:
429
                imgmt->irqenable = OBJECT_DATUM(data);
430
                return (0);
431
        }
432
        return (0); /* Invalid address. */
433
}
434
 
435
/* Read data from kvga and put it in usart output buffer. */
436
void
437
dispatch_vga_to_usart(void *args)
438
{
439
        uint8_t data[MAXBUFLEN];
440
        uint8_t num;
441
 
442
        num = igordev_kvga.read(1, data, MAXBUFLEN);
443
        igordev_usart.write(1, data, num);
444
        while (igordev_usart.write_status != IDEV_STATUS_OK);
445
}
446
 
447
#if ETHERNET_ENABLED
448
struct timer periodic_timer, arp_timer;
449
 
450
void init_network_stuff(void)
451
{
452
        uip_ipaddr_t ipaddr;
453
 
454
        clock_init(); //This also activates global interrupts
455
 
456
        timer_set(&periodic_timer, (clock_time_t)(F_CPU / 2));
457
        timer_set(&arp_timer, (clock_time_t)(F_CPU * 10));
458
 
459
        network_init();
460
 
461
        uip_init();
462
 
463
        uip_ipaddr(ipaddr, 192,168,0,25);
464
        uip_sethostaddr(ipaddr);
465
 
466
        uip_ipaddr(ipaddr, 255,255,255,0);
467
        uip_setnetmask(ipaddr);
468
 
469
        //Init applications
470
        telnetd_init();
471
}
472
 
473
void do_network_stuff(void *args)
474
{
475
        int i;
476
        uip_len = network_read();
477
        if(uip_len > 0) {
478
                if(BUF->type == htons(UIP_ETHTYPE_IP)) {
479
                        uip_arp_ipin();
480
                        uip_input();
481
        /* If the above function invocation resulted in data that
482
           should be sent out on the network, the global variable
483
           uip_len is set to a value > 0. */
484
                        if(uip_len > 0) {
485
                                uip_arp_out();
486
                                network_send();
487
                        }
488
                } else if(BUF->type == htons(UIP_ETHTYPE_ARP)) {
489
                        uip_arp_arpin();
490
        /* If the above function invocation resulted in data that
491
           should be sent out on the network, the global variable
492
           uip_len is set to a value > 0. */
493
                        if(uip_len > 0) {
494
                                network_send();
495
                        }
496
                }
497
 
498
        } else if(timer_expired(&periodic_timer)) {
499
                timer_reset(&periodic_timer);
500
                for(i = 0; i < UIP_CONNS; i++) {
501
                        uip_periodic(i);
502
        /* If the above function invocation resulted in data that
503
           should be sent out on the network, the global variable
504
           uip_len is set to a value > 0. */
505
                        if(uip_len > 0) {
506
                                uip_arp_out();
507
                                network_send();
508
                        }
509
                }
510
 
511
#if UIP_UDP
512
                for(i = 0; i < UIP_UDP_CONNS; i++) {
513
                        uip_udp_periodic(i);
514
        /* If the above function invocation resulted in data that
515
           should be sent out on the network, the global variable
516
           uip_len is set to a value > 0. */
517
                        if(uip_len > 0) {
518
                                uip_arp_out();
519
                                network_send();
520
                        }
521
                }
522
#endif /* UIP_UDP */
523
 
524
        /* Call the ARP timer function every 10 seconds. */
525
                if(timer_expired(&arp_timer)) {
526
                        timer_reset(&arp_timer);
527
                        uip_arp_timer();
528
                }
529
        }
530
        dispatch_request_make(&igordev_telnet, REQ_TYPE_FUNC, 0, DEVTYPE_TELNET,
531
            do_network_stuff);
532
}
533
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.