cortexelf-v1: Make bit flipping array constant
[fw/altos] / src / cortexelf-v1 / ao_1802.c
1 /*
2  * Copyright © 2017 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  */
14
15 #include <ao.h>
16 #include <ao_flip_bits.h>
17 #include <ao_1802.h>
18 #include <ao_exti.h>
19
20 /* Signals muxed between 1802 and STM */
21 uint8_t         MRD, TPB, TPA, MWR;
22
23 /* Decoded address driven by TPA/TPB signals */
24 uint16_t        ADDRESS;
25
26 /* Decoded data, driven by TPB signal */
27 uint8_t         DATA;
28
29 /* Mux control */
30 #define MUX_1802        0
31 #define MUX_STM         1
32
33 uint8_t         MUX_CONTROL;
34
35 /* Signals driven by 1802 only */
36 uint8_t         WAIT, CLEAR, Q, SC, N;
37 uint8_t         DMA_IN, DMA_OUT, INTERRUPT;
38 uint8_t         EF;
39
40 static uint8_t  ma_stm;
41
42 uint8_t
43 MA(void) {
44         if (MUX_CONTROL == MUX_1802)
45                 return (ao_gpio_get_all(MA_PORT) >> MA_SHIFT) & 0xff;
46         else
47                 return ma_stm;
48 }
49
50 static void
51 MA_set(uint8_t ma) {
52         ao_gpio_set_mask(MA_PORT, ((uint16_t) ma) << MA_SHIFT, 0xff << MA_SHIFT);
53         ma_stm = ma;
54 }
55
56 static uint8_t  data_stm;
57
58 static uint8_t
59 DATA_get(void) {
60         if (MUX_CONTROL == MUX_1802)
61                 return ao_flip_bits[(ao_gpio_get_all(DATA_PORT) >> DATA_SHIFT) & 0xff];
62         else
63                 return data_stm;
64 }
65
66 static void
67 DATA_set(uint8_t data) {
68         ao_gpio_set_mask(DATA_PORT, ((uint16_t) ao_flip_bits[data]) << DATA_SHIFT, 0xff << DATA_SHIFT);
69         data_stm = data;
70 }
71
72 static uint8_t
73 N_get(void) {
74         return (ao_gpio_get_all(N_PORT) >> N_SHIFT) & 0x7;
75 }
76
77 static uint8_t
78 EF_get(void) {
79         return (ao_gpio_get_all(EF_PORT) >> EF_SHIFT) & 0xf;
80 }
81
82 static uint8_t
83 Q_get(void) {
84         return ao_gpio_get(Q_PORT, Q_BIT, Q_PIN);
85 }
86
87 static uint8_t
88 SC_get(void) {
89         static const uint8_t flip_sc[4] = { 0, 2, 1, 3 };
90         return flip_sc[(ao_gpio_get_all(SC_PORT) >> SC_SHIFT) & 3];
91 }
92
93 void
94 mrd(uint8_t value) { MRD = value; }
95
96 void
97 mwr(uint8_t value) { MWR = value; }
98
99 void
100 tpb(uint8_t value) {
101         TPB = value;
102
103         /* Latch low address and data on rising edge of TPB */
104         if (TPB) {
105                 ADDRESS = (ADDRESS & 0xff00) | MA();
106                 DATA = DATA_get();
107                 N = N_get();
108                 ao_wakeup(&ADDRESS);
109         }
110 }
111
112 void
113 tpa(uint8_t value) {
114         TPA = value;
115
116         /* Latch high address on rising edge of TPA */
117         if (TPA) {
118                 ADDRESS = (ADDRESS & 0x00ff) | ((uint16_t) MA() << 8);
119                 SC = SC_get();
120                 if (SC == SC_EXECUTE)
121                         EF = EF_get();
122                 ao_wakeup(&ADDRESS);
123         }
124 }
125
126 #define ao_1802_in(port, bit, callback) do {                            \
127                 ao_enable_input(port, bit, 0);                          \
128                 ao_exti_enable(port, bit);                              \
129                 ao_exti_set_callback(port, bit, callback);              \
130                 (*callback)();                                          \
131         } while (0)
132
133 static void mrd_isr(void) { mrd(ao_gpio_get(MRD_PORT, MRD_BIT, MRD_PIN)); }
134 static void mwr_isr(void) { mwr(ao_gpio_get(MWR_PORT, MWR_BIT, MWR_PIN)); }
135 static void tpb_isr(void) { tpb(ao_gpio_get(TPB_PORT, TPB_BIT, TPB_PIN)); }
136 static void tpa_isr(void) { tpa(ao_gpio_get(TPA_PORT, TPA_BIT, TPA_PIN)); }
137 static void q_isr(void) { Q = Q_get(); }
138
139 static void
140 ao_set_1802(void)
141 {
142         ao_gpio_set(MUX_PORT, MUX_BIT, MUX_PIN, 0);
143         ao_1802_in(MRD_PORT, MRD_BIT, mrd_isr);
144         ao_1802_in(MWR_PORT, MWR_BIT, mwr_isr);
145         ao_1802_in(TPB_PORT, TPB_BIT, tpb_isr);
146         ao_1802_in(TPA_PORT, TPA_BIT, tpa_isr);
147         MUX_CONTROL = MUX_1802;
148 }
149
150 static void
151 ao_set_arm(void)
152 {
153         ao_enable_output(MRD_PORT, MRD_BIT, MRD_PIN, 1);
154         ao_enable_output(MWR_PORT, MWR_BIT, MWR_PIN, 1);
155         ao_enable_output(TPB_PORT, TPB_BIT, TPB_PIN, 0);
156         ao_enable_output(TPA_PORT, TPA_BIT, TPA_PIN, 0);
157         ao_gpio_set(MUX_PORT, MUX_BIT, MUX_PIN, 1);
158         MUX_CONTROL = MUX_STM;
159 }
160
161 void
162 ao_1802_control_init(void)
163 {
164         ao_set_1802();
165
166         ao_1802_in(Q_PORT, Q_BIT, q_isr);
167         (void) MA_set;
168         (void) DATA_set;
169         (void) ao_set_arm;
170 }