More Soldering and Drivers
I think I just might be done with soldering. I soldered in a 12 pin header, the 5 connections from the timer CPLD to the header, and 2 posts (pulled from the 12 pin headers that I turned into 11 pin headers) so that I have out of the way ground points for the oscilloscope probes.
I have also been working on the UART drivers and the intel hex (*.ihx) drivers for flash programming.
Now, I’m in the process of a paper self code review.
The UART driver is fairly complex. It has to take a lot of stuff into account: interrupts, initialization, buffers, hardware flow control, support for timeouts and blocking calls.
I wrote this up, but haven’t tested it or even compiled it. Also it has not gone through my initial self code review. But here are the uart.h, uart.c, ringBuffer.h, ringBuffer.c, spi.h, spi.c, gpio.h and gpio.c.
NOTE! Not tested or even compiled. The code below is guaranteed to fail. Do NOT copy and paste this thinking this is a working solution. You are free to copy and paste it–just don’t expect it to work. When it’s working, I’ll post more. It is just to give you an idea of what I’m working on at the moment.
uart.h:
1 #ifndef INCLUDE_DRIVER_UART_H
2 #define INCLUDE_DRIVER_UART_H
3
4 #include "common.h"
5
6 // Initialize the UART. Note that the MAX3110E may take 25ms
7 // to stablize. So it may fail when called to early. Call until
8 // it returns true.
9 bool uartInit(uint16_t config);
10
11 // Reconfigure the UART
12 bool uartReconfig(uint16_t config);
13
14 // Adds b to the transmit buffer. Then attempts to send.
15 // Return true if successful or false if an error was
16 // encountered. If the error has a new UART_ERROR_TX_OVERFLOW bit,
17 // the the byte was not added.
18 // It is not a blocking function.
19 bool send(uint8_t b);
20
21 // Removes a byte from the receive buffer and returns in *pByte.
22 // returns true if successful or false an error was encountered
23 // If *pByte is -1, the buffer was empty but this does NOT indicate
24 // an error.
25 bool recv(int16_t* pByte);
26
27 // Block until something interesting happens. It won't necessarily be the desired event so the
28 // user still has to check. Also, released on system tick.
29 void pend();
30
31 // Sets/clears RTS. Use to stop transmission before doing something that may cause buffer overflow
32 bool setRTS(bool ready);
33
34 // Bit locations in the error status
35 #define UART_ERROR_INITIALIZATION_BIT (0)
36 #define UART_ERROR_RX_OVERFLOW_BIT (1)
37 #define UART_ERROR_FRAMING_BIT (2)
38 #define UART_ERROR_PARITY_BIT (3)
39 #define UART_ERROR_TX_OVERFLOW_BIT (4)
40
41 // Gets the current errors. Also, clears any error bits sent in clear.
42 // If any of the UART calls return false, then this should be called to clear the error
43 // state before another call.
44 uint16_t uartErrorReadAndClear(uint16_t clear);
45
46 // UART Config
47 // Use these bits and BAUD rates with uartInit and uartReconfig
48 #define UART_BAUD_300 (0x0f)
49 #define UART_BAUD_600 (0x0e)
50 #define UART_BAUD_1200 (0x0d)
51 #define UART_BAUD_2400 (0x0c)
52 #define UART_BAUD_4800 (0x0b)
53 #define UART_BAUD_9600 (0x0a)
54 #define UART_BAUD_19200 (0x09)
55 #define UART_BAUD_14400 (0x03)
56 #define UART_BAUD_28800 (0x02)
57 #define UART_BAUD_38400 (0x08)
58 #define UART_BAUD_57600 (0x01)
59 #define UART_BAUD_115200 (0x00)
60 #define UART_7_BIT_WORDS_BIT (4)
61 #define UART_PARITY_ENABLE_BIT (5)
62 #define UART_TWO_STOP_BITS_BIT (6)
63 //#define UART_IRDA_MODE_BIT (7)
64 #define UART_RAM_INTERRUPT_BIT (8)
65 #define UART_PM_INTERRUPT_BIT (9)
66 #define UART_RM_INTERRUPT_BIT (10)
67 #define UART_TM_INTERRUPT_BIT (11)
68 //#define UART_FIFO_DISABLE_BIT (13)
69
70 #define RESET_BIT(x, b) x &= ~(1<<b)
71 #define SET_BIT(x, b) x |= (1<<b)
72 #define SET_BIT_BY(x, b, v) x = (v ? (x | (1<<b)) : (x & ~(1<<b)))
73 #define IS_BIT(x, b) ((x & (1<<b)) != 0)
74
75 #endif
uart.c:
1 #include "gpio.h"
2 #include "spi.h"
3 #include "uart.h"
4 #include "ringBuffer.h"
5
6 // The UART code handles communication between the board and a PC
7 // It provides open/close/read/write. The read and write functions are
8 // blocking, but ring buffers enable some degree of buffering.
9 // The hardware supports CTS/RTS flow control
10 // Possible errors are read overflow, framing, parity
11 // Supported baud rates are 115.2K, 57.6K, 38.4K 19.2K 9600, 4800, 1200, 300
12 // Initialization may require several calls as the HW takes up to 25 ms
13 // to stabilize.
14
15 #define UART_RECV_RING_BUFFER_SIZE (64)
16 #define UART_XMIT_RING_BUFFER_SIZE (64)
17
18 // For hardware flow control, set these:
19 // Stop threshold is the number of bytes used in the receive buffer above
20 // which RTS is deasserted. It must be less than UART_RECV_RING_BUFFER_SIZE
21 // Note that there is an 8 byte FIFO in the MAX3110E and that every write
22 // necessetates a read because of the exchange way the chip works
23 #define UART_RECV_RTS_STOP_THRESHOLD (UART_RECV_RING_BUFFER_SIZE - 12)
24
25 // The restart provides a little bit of hysteresis for RTS control
26 // It must be less than UART_RECV_RTS_STOP_THRESHOLD
27 #define UART_RECV_RTS_RESTART_THRESHOLD (UART_RECV_RTS_STOP_THRESHOLD - 8)
28
29 // UART Read/Write
30 #define UART_PARITY_BIT_BIT (8)
31 #define UART_RTS_CTS_BIT (9)
32 #define UART_FRAMING_ERROR_BIT (10)
33 #define UART_TRANSMIT_ENABLE_BIT (10)
34
35 // UART Common
36 #define UART_TRANSMIT_EMPTY_BIT (14)
37 #define UART_DATA_READY_BIT (15)
38
39 uint16_t uartConfig = 0;
40
41 uint8_t recvRingBuffer[UART_RECV_RING_BUFFER_SIZE];
42 uint8_t xmitRingBuffer[UART_XMIT_RING_BUFFER_SIZE];
43
44 struct RingBuffer rxBuffer;
45 struct RingBuffer txBuffer;
46
47 #define UART_STATE_WAITING_ON_CTS (0)
48 //#define UART_STATE_WAITING_ON_RX_HW (1)
49 #define UART_STATE_WAITING_ON_TX_HW (2)
50 #define UART_STATE_REQ_RTS_CHANGE (3)
51 #define UART_STATE_REQ_RTS_LEVEL (4)
52 #define UART_STATE_REQ_RM_CHANGE (5)
53 #define UART_STATE_REQ_RM_LEVEL (6)
54 #define UART_STATE_REQ_RAM_CHANGE (7)
55 #define UART_STATE_REQ_RAM_LEVEL (8)
56 //#define UART_STATE_WAITING_ON_RX_RB (9)
57 //#define UART_STATE_WAITING_ON_TX_RB (10)
58 #define UART_STATE_USER_RTS (11)
59 #define UART_STATE_PENDING (12)
60 uint16_t uartState;
61
62 #define UART_ERROR_TO_REPORT_BIT (15)
63 int uartError;
64
65 uint16_t writeUartConfig(uint16_t config);
66 uint16_t readUartConfig();
67 uint16_t writeAndReadUart(uint8_t b);
68 uint16_t readUart();
69
70 ///////////////////////////////////////////////////
71 //
72 // Interface functions
73 //
74
75
76 // Initialize the UART. Note that the MAX3110E may take 25ms
77 // to stablize. So it may fail when called to early. Call until
78 // it returns true
79 bool uartInit(uint16_t config)
80 {
81 bool success;
82
83 // initial state
84 uartState = (1 << UART_STATE_WAITING_ON_TX_HW);
85
86 // create reing buffers
87 ringBufferInit(&rxBuffer, recvRingBuffer, sizeof(recvRingBuffer));
88 ringBufferInit(&txBuffer, xmitRingBuffer, sizeof(xmitRingBuffer));
89
90 // Config part
91 return uartReconfig(config);
92 }
93
94 // Reconfigure the UART (baud, stop bits, parity, bits per word,
95 bool uartReconfig(uint16_t config)
96 {
97 bool success;
98 uartConfig = config & 0xc000;
99 writeUartConfig(config);
100 success = ((config ^ readUartConfig()) & ~0xc000) == 0;
101 SET_BIT_BY(uartError, UART_ERROR_INITIALIZATION_BIT, success);
102 RESET_BIT(uartError, UART_ERROR_TO_REPORT_BIT); // reporting now
103 return success;
104 }
105
106 // Sends b out the serial port.
107 // If there are bytes in the xmit buffer, it is added.
108 // IF the xmit buffer is empty and the UARt can take a byte,
109 // then the byte is written out.
110 // If the byte cannot be written out, it is added to the xmit
111 // buffer.
112 bool send(uint8_t b)
113 {
114 if (!ringBufferFull(&txBuffer))
115 {
116 ringBufferEnqueue(&txBuffer, b);
117 }
118 else
119 {
120 SET_BIT(uartError, UART_ERROR_TX_OVERFLOW_BIT);
121 }
122 RESET_BIT(uartError, UART_ERROR_TO_REPORT_BIT); // reporting
123 return (uartError & 0x7fff) != 0;
124 }
125
126 // A non-blocking recv. It returns true if OK, false if an error
127 // The pByte will get (int)-1 if there is nothing to receive
128 // If an error has occured, return false // TODO
129 // If the recv buffer is not empty, dequeue and return
130 // Else set the read pending bit and spin wait
131 bool recv(int16_t *pByte)
132 {
133 if (!ringBufferEmpty(&rxBuffer))
134 {
135 *pByte = ringBufferDequeue(&rxBuffer);
136
137 // if falls below RTS threshold, then turn RTS back on
138 if (IS_BIT(uartState, UART_STATE_REQ_RTS_LEVEL) && !IS_BIT(uartState, UART_STATE_USER_RTS))
139 {
140 if (ringBufferCount(&rxBuffer) < UART_RECV_RTS_RESTART_THRESHOLD)
141 {
142 SET_BIT(uartState, UART_STATE_REQ_RTS_CHANGE);
143 SET_BIT(uartState, UART_STATE_REQ_RTS_LEVEL);
144 }
145 }
146 }
147 else
148 {
149 *pByte = -1;
150 }
151 RESET_BIT(uartError, UART_ERROR_TO_REPORT_BIT); // reporting
152 return (uartError & 0x7fff) != 0;
153 }
154
155 // Use for creating blocking calls. The user can pass an idle function and a pointer that will be
156 // continually called until the call ends
157 void pend(void(*cbIdleFn)(void* p), void* p)
158 {
159 SET_BIT(uartState, UART_STATE_PENDING);
160 while (IS_BIT(uartState, UART_STATE_PENDING))
161 {
162 // Do nothing or do idle
163 if (cbIdleFn)
164 {
165 cbIdleFn(p);
166 }
167 }
168 }
169
170 void configRTS(bool config)
171 {
172 // if turning back on, only request change if off and threshold is not met
173 SET_BIT(uartState, UART_STATE_USER_RTS, config);
174
175 bool reqLevel = config && ringBufferCount(&txBuffer) < UART_RECV_RTS_STOP_THRESHOLD;
176 bool curLevel = IS_BIT(uartState, UART_STATE_REQ_RTS_LEVEL);
177 if (reqLevel != curLevel)
178 {
179 SET_BIT(uartState, UART_STATE_REQ_RTS_CHANGE);
180 SET_BIT_BY(uartState, UART_STATE_REQ_RTS_LEVEL, reqLevel);
181 readWrite();
182 }
183 }
184
185 uint16_t uartErrorReadAndClear(uint16_t clear)
186 {
187 uartError &= ~clear;
188 return uartError;
189 }
190
191 ///////////////////////////////////////////////////
192 //
193 // Internal functions
194 //
195
196 // This is the work horse function that does the actual reading and writing through the UART.
197 // It handles the RX, TX, RTS, CTS, errors, interrupt enables,
198 bool readWrite()
199 {
200 uint16_t read;
201 uint16_t write = 0;
202 bool te = false; // use readWrite instead of read, but if nothing to write, use TE#
203 bool loop = true;
204 bool wrote = false;
205 bool errorOccured = false;
206 while (loop)
207 {
208 loop = false;
209
210 // See if reconfig is necesary
211 if (uartState & ((1 << UART_STATE_REQ_RM_CHANGE) | (1 << UART_STATE_REQ_RAM_CHANGE)))
212 {
213 // clear requests
214 uartState &= ~((1 << UART_STATE_REQ_RM_CHANGE) | (1 << UART_STATE_REQ_RAM_CHANGE));
215
216 if (uartState & (1 << UART_STATE_REQ_RM_CHANGE))
217 {
218 SET_BIT_BY(uartConfig, UART_RM_INTERRUPT_BIT, IS_BIT(uartState, UART_STATE_REQ_RM_LEVEL));
219 }
220 if (uartState & (1 << UART_STATE_REQ_RAM_CHANGE))
221 {
222 SET_BIT_BY(uartConfig, UART_RAM_INTERRUPT_BIT, IS_BIT(uartState, UART_STATE_REQ_RAM_LEVEL));
223 }
224 writeUartConfig(uartConfig);
225 }
226
227 // See if reconfig is necesary
228 write = 0x0000;
229 if (IS_BIT(uartState, UART_STATE_REQ_RTS_CHANGE))
230 {
231 SET_BIT_BY(write, UART_RTS_CTS_BIT, IS_BIT(uartState, UART_STATE_REQ_RTS_LEVEL));
232 te = true;
233 }
234 if (!wrote && (uartState & ((1 << UART_STATE_WAITING_ON_CTS) | (1 << UART_STATE_WAITING_ON_TX_HW))) == 0)
235 {
236 wrote = true; // We'll write once per call to this function because the HW has a read FIFO but not a write FIFO, so may read multiples
237 if (!ringBufferEmpty(&txBuffer))
238 {
239 uint8_t b = ringBufferDequeue(&txBuffer);
240 write |= 0x8000 | b;
241 te = false; // if requestiung a TE# write, no need because we're writing anyway
242 }
243 }
244
245 // When there is nithing to write, but we want to update RTS, we need to set the
246 // UART_TRANSMIT_ENABLE_BIT in the write side exchange
247 if (te)
248 {
249 te = false;
250 write |= 0x8000 | (1 << UART_TRANSMIT_ENABLE_BIT);
251 }
252 read = writeAndReadUart(write);
253
254 if (IS_BIT(read, UART_FRAMING_ERROR_BIT))
255 {
256 if (IS_BIT(uartState, UART_STATE_REQ_RAM_LEVEL))
257 {
258 SET_BIT(uartState, UART_STATE_REQ_RAM_CHANGE);
259 SET_BIT(uartState, UART_STATE_REQ_RAM_LEVEL);
260 SET_BIT(uartError, UART_ERROR_FRAMING_BIT);
261 loop = true; // need to change RAM
262 errorOccured = true;
263 }
264 }
265 else if (IS_BIT(uartState, UART_STATE_REQ_RAM_LEVEL))
266 {
267 SET_BIT(uartState, UART_STATE_REQ_RAM_CHANGE);
268 RESET_BIT(uartState, UART_STATE_REQ_RAM_LEVEL);
269 loop = true; // need to change RAM
270 }
271
272 // keep track of last T bit
273 SET_BIT_BY(uartState, UART_STATE_WAITING_ON_TX_HW, IS_BIT(read, UART_TRANSMIT_EMPTY_BIT));
274
275 // keep track of CTS
276 SET_BIT_BY(uartError, UART_STATE_WAITING_ON_CTS, IS_BIT(read, UART_RTS_CTS_BIT));
277
278 if (IS_BIT(read, UART_PARITY_BIT_BIT))
279 {
280 SET_BIT(uartError, UART_ERROR_PARITY_BIT);
281 errorOccured = true;
282 }
283
284
285 if (IS_BIT(read, UART_DATA_READY_BIT))
286 {
287 if (!ringBufferFull(&rxBuffer))
288 {
289 ringBufferEnqueue(&rxBuffer, (uint8_t)read);
290 if (!IS_BIT(uartConfig, UART_STATE_REQ_RTS_LEVEL) && ringBufferCount(&rxBuffer) >= UART_RECV_RTS_STOP_THRESHOLD)
291 {
292 // buffer getting too full, lets hold off on
293 SET_BIT(uartState, UART_STATE_REQ_RTS_CHANGE);
294 RESET_BIT(uartState, UART_STATE_REQ_RTS_LEVEL);
295 SET_BIT(uartState, UART_STATE_REQ_RM_CHANGE);
296 RESET_BIT(uartState, UART_STATE_REQ_RM_LEVEL);
297 loop = true; // need to take down RTS
298 }
299 }
300 else
301 {
302 SET_BIT(uartError, UART_ERROR_RX_OVERFLOW_BIT);
303 errorOccured = true;
304 }
305 }
306 }
307 if (errorOccured)
308 {
309 SET_BIT(uartError, UART_ERROR_TO_REPORT_BIT);
310 }
311 }
312
313
314 // UART ISR
315 // called from the actual ISR, so this one doesn't end in reti
316 void uartIsr()
317 {
318 // Do the read/write which will clear R&RM, T&TM, and RA&RAM, and update the RX buffers, and
319 // send a byte if there is one on the TX buffer
320 readWrite();
321
322 // This ISR might be called on any ISR, so it's possible that nothing interesting happened.
323 // It is also called on system tick, so even though the UART has no information, it
324 // is possible to take advantage of this to implement timeouts
325 RESET_BIT(uartState, UART_STATE_PENDING);
326 }
327
328 ///////////////////////////////////////////////////
329 //
330 // Low Level functions
331 //
332
333 uint16_t writeUartConfig(uint16_t config)
334 {
335 uartConfig = config & 0x3fff;
336 return uartExchange(0xC000 | uartConfig);
337 }
338
339 uint16_t readUartConfig()
340 {
341 return uartExchange(0x4000 | uartConfig);
342 }
343
344 uint16_t writeAndReadUart(uint16_t write)
345 {
346 return uartExchange(0x8000 | write);
347 }
348
349 uint16_t readUart()
350 {
351 return uartExchange(0x0000);
352 }
353
354 // Low level function that used the SPI/GPIO module to exchange a 16 word
355 // with the MAX3110E
356 uint16_t uartExchange(uint16_t write)
357 {
358 uint16_t read;
359 gpioWriteLevel(0, false);
360 read = spiExchange((uint8_t)(write >> 8), SPI_SHIFT_TO_MSB, 8);
361 read <<= 8;
362 read |= spiExchange((uint8_t)(write), SPI_SHIFT_TO_MSB, 8);
363 gpioWriteLevel(1, false);
364 }
ringBuffer.h:
1 #ifndef INCLUDE_RING_BUFFER_H
2 #define INCLUDE_RING_BUFFER_H
3
4 #include "common.h"
5
6 struct RingBuffer
7 {
8 uint8_t* buffer;
9 int count;
10 int enqueuePoint;
11 int dequeuePoint;
12 };
13
14 // Prepare a ring buffer for use
15 void ringBufferInit(struct RingBuffer* rb, uint8_t* buffer, int count);
16
17 // Query if ring buffer is empty
18 bool ringBufferIsEmpty(struct RingBuffer* rb);
19
20 // Query if ring buffer is full
21 bool ringBufferIsFull(struct RingBuffer* rb);
22
23 // Query number of items in ring buffer
24 int ringBufferCount(struct RingBuffer* rb);
25
26 // Add a byte into the ring buffer
27 void ringBufferEnqueue(struct RingBuffer* rb, uint8_t b);
28
29 // Gets an item if available. The user can send an optional
30 // pointer to bool which will be true if data was retrieved
31 uint8_t ringBufferDequeue(struct RingBuffer* rb);
32 #endif
ringBuffer.c:
1 #include "ringBuffer.h"
2
3
4 // This is a ring buffer for uint8_t of arbitrary length
5 // It is empty when enqueuePoint == dequeuePoint
6
7
8 // Initialize a new ring buffer. User supplies
9 void ringBufferInit(struct RingBuffer* rb, uint8_t* buffer, int count)
10 {
11 rb->buffer = buffer;
12 rb->count = count;
13 rb->enqueuePoint = 0;
14 rb->dequeuePoint = 0;
15 }
16
17 bool ringBufferIsEmpty(struct RingBuffer* rb)
18 {
19 return rb->enqueuePoint == rb->dequeuePoint;
20 }
21
22 // The buffer is full if the enqueuePoint is one less than the dequeue
23 // point. If the dequeue point is 0, then the
24 bool ringBufferIsFull(struct RingBuffer* rb) __critical
25 {
26 int diff = rb->dequeuePoint - rb->enqueuePoint;
27 return diff == 1 || ((diff + rb->count) == 1);
28 }
29
30 // Gets the number of items in the ring buffer
31 int ringBufferCount(struct RingBuffer* rb) __critical
32 {
33 int diff = rb->dequeuePoint - rb->enqueuePoint;
34 if (diff < 0)
35 {
36 diff += rb->count;
37 }
38 return diff;
39 }
40
41 // Adds a point to the ring buffer if space is available
42 // Returns true if the item was successfully added
43 void ringBufferEnqueue(struct RingBuffer* rb, uint8_t b) __critical
44 {
45 assert(!ringBufferIsFull(rb));
46 int p = rb->enqueuePoint;
47 rb->buffer[p] = b;
48 if (p == (rb->count - 1))
49 {
50 p = 0;
51 }
52 else
53 {
54 p++;
55 }
56 rb->enqueuePoint = p;
57 }
58
59 // Gets an item if available. The user can send an optional
60 // pointer to bool which will be true if data was retrieved
61 uint8_t ringBufferDequeue(struct RingBuffer* rb) __critical
62 {
63 uint8_t b = 0;
64 assert(!ringBufferIsEmpty(rb));
65 int p = rb->dequeuePoint;
66 b = rb->buffer[p];
67 if (p == (rb->count - 1))
68 {
69 p = 0;
70 }
71 else
72 {
73 p++;
74 }
75 rb->dequeuePoint = p;
76
77 return b;
78 }
spi.h:
1 #ifndef INCLUDE_DRIVER_SPI_H
2 #define INCLUDE_DRIVER_SPI_H
3
4 #include "common.h"
5
6 #define SPI_SHIFT_TO_MSB (0x20)
7 #define SPI_SHIFT_TO_LSB (0x00)
8
9 #define SPI_DEFAULT_HIGH (0x00)
10 #define SPI_DEFAULT_LOW (0x00)
11
12 #define SPI_INVERT_SCK (0x00)
13 #define SPI_DIRECT_SCK (0x00)
14
15 // Exchange 0-8 bits on SPI
16 uint8_t spiExchange(uint8_t b, uint8_t flags, uint8_t count);
17
18 #endif
spi.c:
1 #include "spi.h"
2
3 Z80_IO_PORT(SPI_REG, 0x83);
4 Z80_IO_PORT(SPI_CTRL, 0x84);
5
6 // Exchange 0-8 bits on SPI
7 uint8_t spiExchange(uint8_t b, uint8_t flags, uint8_t count)
8 {
9 SPI_REG = b;
10 SPI_CTRL = flags | count;
11
12 // delay for SPI clock
13 __asm__("nop");
14 __asm__("nop");
15 __asm__("nop");
16 __asm__("nop");
17
18 return SPI_REG;
19 }
gpio.h:
1 #ifndef INCLUDE_DRIVER_GPIO_H
2 #define INCLUDE_DRIVER_GPIO_H
3
4 #include "common.h"
5
6 // Gets the direction 0=in, 1=out of GPIO number 'bit' which is 0-7
7 bool gpioReadDirection(int bit);
8
9 // Writes the direction 0=in, 1=out of GPIO number 'bit' which is 0-7
10 void gpioWriteDirection(int bit, bool out);
11
12 // Gets the level to drive if GPIO 'bit' is an output
13 bool gpioReadOutLevel(int bit);
14
15 // Sets the level to drive if GPIO 'bit' is an output
16 void gpioWriteLevel(int bit, bool out);
17
18 // Gets the actual level of GPIO 'bit'
19 bool gpioReadInLevel(int bit);
20
21 #endif
gpio.c:
1 #include "gpio.h"
2
3 Z80_IO_PORT(GPIO_DIR, 0x80);
4 Z80_IO_PORT(GPIO_OUT, 0x81);
5 Z80_IO_PORT(GPIO_IN, 0x82);
6
7 // Gets the direction 0=in, 1=out of GPIO number 'bit' which is 0-7
8 bool gpioReadDirection(int bit)
9 {
10 assert(bit >= 0 && bit < 7);
11 return (GPIO_DIR & (1 << bit)) != 0;
12 }
13
14 // Writes the direction 0=in, 1=out of GPIO number 'bit' which is 0-7
15 void gpioWriteDirection(int bit, bool out)
16 {
17 int b;
18 assert(bit >= 0 && bit < 7);
19 b = GPIO_DIR;
20 if (out)
21 {
22 b |= (1 << bit);
23 }
24 else
25 {
26 b &= ~(1 << bit);
27 }
28 GPIO_DIR = b;
29 }
30
31 // Gets the level to drive if GPIO 'bit' is an output
32 bool gpioReadOutLevel(int bit)
33 {
34 assert(bit >= 0 && bit < 7);
35 return (GPIO_OUT & (1 << bit)) != 0;
36 }
37
38 // Sets the level to drive if GPIO 'bit' is an output
39 void gpioWriteLevel(int bit, bool out)
40 {
41 int b;
42 assert(bit >= 0 && bit < 7);
43 b = GPIO_OUT;
44 if (out)
45 {
46 b |= (1 << bit);
47 }
48 else
49 {
50 b &= ~(1 << bit);
51 }
52 GPIO_OUT = b;
53 }
54
55 // Gets the actual level of GPIO 'bit'
56 bool gpioReadInLevel(int bit)
57 {
58 assert(bit >= 0 && bit < 7);
59 return (GPIO_IN & (1 << bit)) != 0;
60 }