Makefiles: Separate simavr.pc and simavr-avr.pc
[simavr] / simavr / sim / avr_lin.c
1 /*
2         avr_lin.h
3
4         Copyright 2008, 2011 Michel Pollet <buserror@gmail.com>
5         Copyright 2011 Markus Lampert  <mlampert@telus.net>
6
7         This file is part of simavr.
8
9         simavr is free software: you can redistribute it and/or modify
10         it under the terms of the GNU General Public License as published by
11         the Free Software Foundation, either version 3 of the License, or
12         (at your option) any later version.
13
14         simavr is distributed in the hope that it will be useful,
15         but WITHOUT ANY WARRANTY; without even the implied warranty of
16         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17         GNU General Public License for more details.
18
19         You should have received a copy of the GNU General Public License
20         along with simavr.  If not, see <http://www.gnu.org/licenses/>.
21  */
22
23 #include <stdio.h>
24 #include "avr_lin.h"
25
26
27 static void
28 avr_lin_baud_write(
29         struct avr_t *avr,
30         avr_io_addr_t addr,
31         uint8_t v,
32         void *param)
33 {
34         avr_lin_t *p = (avr_lin_t*) param;
35
36         if (p->r_linbtr != p->ldisr.reg || p->r_linbtr != p->lbt.reg) { // sanity check
37                 AVR_LOG(avr, LOG_ERROR, "LIN: LDISR and LBT[x] register different!\n");
38                 return;
39         }
40
41         AVR_LOG(avr, LOG_TRACE, "LIN: addr[%04x] = %02x\n", addr, v);
42         if (addr == p->ldisr.reg) {
43                 if (avr_regbit_get(avr, p->lena)) {
44                         AVR_LOG(avr, LOG_WARNING, "LIN: LENA bit set on changing LBTR\n");
45                         return;
46                 }
47                 if ((v >> p->ldisr.bit) & p->ldisr.mask) {
48                         uint8_t lbt = (v >> p->lbt.bit) & p->lbt.mask;
49                         uint8_t ov = v;
50                         v = (1 << p->ldisr.bit) | (lbt << p->lbt.bit);
51                         AVR_LOG(avr, LOG_TRACE, "LIN: v=%02x -> LBT = %02x -> LINBT = %02x\n", ov, lbt, v);
52                 } else {
53                         v = 0x20;
54                 }
55         }
56         avr_core_watch_write(avr, addr, v); // actually set the value
57
58         uint32_t lbt = avr_regbit_get(avr, p->lbt);
59         uint32_t lbrr = (avr->data[p->r_linbrrh] << 8) | avr->data[p->r_linbrrl];
60         AVR_LOG(avr, LOG_TRACE, "LIN: UART LBT/LBRR to %04x/%04x\n", lbt, lbrr);
61         uint32_t baud = avr->frequency / (lbt * (lbrr + 1));
62         uint32_t word_size = 1 /*start*/+ 8 /*data bits*/+ 1 /*parity*/+ 1 /*stop*/;
63
64         AVR_LOG(avr, LOG_TRACE, "LIN: UART configured to %04x/%04x = %d bps, 8 data 1 stop\n", lbt,
65                 lbrr, baud);
66
67         p->uart.usec_per_byte = 1000000 / (baud / word_size);
68         AVR_LOG(avr, LOG_TRACE, "LIN: Roughly %d usec per bytes\n", (int) p->uart.usec_per_byte);
69 }
70
71 static void
72 avr_lin_reset(
73                 avr_io_t *port)
74 {
75         avr_lin_t *p = (avr_lin_t*) port;
76         avr_t * avr = p->io.avr;
77
78         AVR_LOG(avr, LOG_TRACE, "LIN: UART: reset\n");
79
80         p->uart.io.reset(&p->uart.io);
81         avr->data[p->r_linbtr] = 0x20;
82 }
83
84 static avr_io_t _io = {
85                 .kind = "lin",
86                 .reset = avr_lin_reset,
87 };
88
89 void
90 avr_lin_init(
91                 avr_t *avr,
92                 avr_lin_t *p)
93 {
94         // init uart part
95         avr_uart_init(avr, &p->uart);
96
97         p->io = _io;
98         avr_register_io_write(avr, p->r_linbtr, avr_lin_baud_write, p);
99         avr_register_io_write(avr, p->r_linbrrl, avr_lin_baud_write, p);
100         avr->data[p->r_linbtr] = 0x20;
101 }