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 }