SPM: Added Self Programming Instruction & Support
[simavr] / simavr / sim / avr_flash.c
1 /*
2         avr_flash.c
3
4         Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
5
6         This file is part of simavr.
7
8         simavr is free software: you can redistribute it and/or modify
9         it under the terms of the GNU General Public License as published by
10         the Free Software Foundation, either version 3 of the License, or
11         (at your option) any later version.
12
13         simavr is distributed in the hope that it will be useful,
14         but WITHOUT ANY WARRANTY; without even the implied warranty of
15         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16         GNU General Public License for more details.
17
18         You should have received a copy of the GNU General Public License
19         along with simavr.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include "avr_flash.h"
26
27 static avr_cycle_count_t avr_progen_clear(struct avr_t * avr, avr_cycle_count_t when, void * param)
28 {
29         avr_flash_t * p = (avr_flash_t *)param;
30         avr_regbit_clear(p->io.avr, p->selfprgen);
31         printf("avr_progen_clear - SPM not received, clearing PRGEN bit\n");
32         return 0;
33 }
34
35 static uint8_t avr_flash_read(struct avr_t * avr, avr_io_addr_t addr, void * param)
36 {
37         avr_flash_t * p = (avr_flash_t *)param;
38         uint8_t v = avr_core_watch_read(avr, addr);
39         printf("avr_flash_read %02x\n", v);
40         return v;
41 }
42
43 static void avr_flash_write(avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param)
44 {
45         avr_flash_t * p = (avr_flash_t *)param;
46
47         avr_core_watch_write(avr, addr, v);
48
49 //      printf("** avr_flash_write %02x\n", v);
50
51         if (avr_regbit_get(avr, p->selfprgen))
52                 avr_cycle_timer_register(avr, 4, avr_progen_clear, p); // 4 cycles is very little!
53 }
54
55 static int avr_flash_ioctl(struct avr_io_t * port, uint32_t ctl, void * io_param)
56 {
57         if (ctl != AVR_IOCTL_FLASH_SPM)
58                 return -1;
59
60         avr_flash_t * p = (avr_flash_t *)port;
61         avr_t * avr = p->io.avr;
62
63         uint16_t z = avr->data[R_ZL] | (avr->data[R_ZH] << 8);
64         uint16_t r01 = avr->data[0] | (avr->data[1] << 8);
65
66 //      printf("AVR_IOCTL_FLASH_SPM %02x Z:%04x R01:%04x\n", avr->data[p->r_spm], z,r01);
67         avr_cycle_timer_cancel(avr, avr_progen_clear, p);
68         avr_regbit_clear(avr, p->selfprgen);
69         if (avr_regbit_get(avr, p->pgers)) {
70                 z &= ~1;
71                 printf("Erasing page %04x (%d)\n", (z / p->spm_pagesize), p->spm_pagesize);
72                 for (int i = 0; i < p->spm_pagesize; i++)
73                         avr->flash[z++] = 0xff;
74         } else if (avr_regbit_get(avr, p->pgwrt)) {
75                 z &= ~1;
76                 printf("Writing page %04x (%d)\n", (z / p->spm_pagesize), p->spm_pagesize);
77         } else if (avr_regbit_get(avr, p->blbset)) {
78                 printf("Settting lock bits (ignored)\n");
79         } else {
80                 z &= ~1;
81                 avr->flash[z++] = r01;
82                 avr->flash[z++] = r01 >> 8;
83         }
84         return 0;
85 }
86
87 static  avr_io_t        _io = {
88         .kind = "flash",
89         .ioctl = avr_flash_ioctl,
90 };
91
92 void avr_flash_init(avr_t * avr, avr_flash_t * p)
93 {
94         p->io = _io;
95         printf("%s init SPM %04x\n", __FUNCTION__, p->r_spm);
96
97         avr_register_io(avr, &p->io);
98         avr_register_vector(avr, &p->flash);
99
100         avr_register_io_write(avr, p->r_spm, avr_flash_write, p);
101 //      avr_register_io_read(avr, p->r_spm, avr_flash_read, p);
102 }
103