ibmpc: ringbuf optimization for cpp

This commit is contained in:
tmk 2021-07-06 22:29:26 +09:00
parent bff5cff1f2
commit 369b5cb21e
2 changed files with 55 additions and 20 deletions

View file

@ -69,7 +69,6 @@ void IBMPC::host_init(void)
inhibit();
int_init();
int_off();
ringbuf_init(&rb, rbuf, RINGBUF_SIZE);
host_isr_clear();
}
@ -174,14 +173,14 @@ int16_t IBMPC::host_recv(void)
int16_t ret = -1;
// Enable ISR if buffer was full
if (ringbuf_is_full(&rb)) {
if (ringbuf_is_full()) {
host_isr_clear();
int_on();
idle();
}
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
ret = ringbuf_get(&rb);
ret = ringbuf_get();
}
if (ret != -1) dprintf("r%02X ", ret&0xFF);
return ret;
@ -204,7 +203,7 @@ void IBMPC::host_isr_clear(void)
protocol = 0;
error = 0;
isr_state = 0x8000;
ringbuf_reset(&rb);
ringbuf_reset();
}
inline void IBMPC::isr(void)
@ -281,8 +280,8 @@ inline void IBMPC::isr(void)
uint8_t us = 100;
// wait for rising and falling edge of b7 of XT_IBM
if (!protocol) {
while (!(IBMPC_CLOCK_PIN&(1<<clock_bit)) && us) { wait_us(1); us--; }
while ( IBMPC_CLOCK_PIN&(1<<clock_bit) && us) { wait_us(1); us--; }
while (!(IBMPC_CLOCK_PIN & clock_mask) && us) { wait_us(1); us--; }
while ( (IBMPC_CLOCK_PIN & clock_mask) && us) { wait_us(1); us--; }
} else if (protocol == IBMPC_PROTOCOL_XT_CLONE) {
us = 0;
}
@ -311,8 +310,8 @@ inline void IBMPC::isr(void)
uint8_t us = 100;
// wait for rising and falling edge of AT stop bit to discriminate between XT and AT
if (!protocol) {
while (!(IBMPC_CLOCK_PIN&(1<<clock_bit)) && us) { wait_us(1); us--; }
while ( IBMPC_CLOCK_PIN&(1<<clock_bit) && us) { wait_us(1); us--; }
while (!(IBMPC_CLOCK_PIN & clock_mask) && us) { wait_us(1); us--; }
while ( (IBMPC_CLOCK_PIN & clock_mask) && us) { wait_us(1); us--; }
} else if (protocol == IBMPC_PROTOCOL_XT_IBM) {
us = 0;
}
@ -363,15 +362,17 @@ inline void IBMPC::isr(void)
DONE:
// store data
if (!ringbuf_put(&rb, isr_state & 0xFF)) {
// buffer overflow
error = IBMPC_ERR_FULL;
ringbuf_put(isr_state & 0xFF);
if (ringbuf_is_full()) {
// Disable ISR if buffer is full
int_off();
// inhibit: clock_lo() instead of inhibit() for ISR optimization
clock_lo();
}
if (ringbuf_is_empty()) {
// buffer overflow
error = IBMPC_ERR_FULL;
}
ERROR:
// clear for next data
isr_state = 0x8000;
@ -388,9 +389,9 @@ void IBMPC::host_set_led(uint8_t led)
}
// NOTE: With this ISR data line can be read within 2us after clock falling edge.
// To read data line early as possible:
// write naked ISR with asembly code to read the line and call C func to do other job?
// NOTE: With this ISR data line should be read within 5us after clock falling edge.
// Confirmed that ATmega32u4 can read data line in 2.5us from interrupt after
// ISR prologue pushs r18, r19, r20, r21, r24, r25 r30 and r31 with GCC 5.4.0
ISR(IBMPC_INT_VECT)
{
IBMPC::interface0.isr();

View file

@ -40,7 +40,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include <stdbool.h>
#include "wait.h"
#include "ringbuf.h"
/*
* IBM PC keyboard protocol
@ -91,8 +90,6 @@ POSSIBILITY OF SUCH DAMAGE.
#define IBMPC_LED_NUM_LOCK 1
#define IBMPC_LED_CAPS_LOCK 2
#define RINGBUF_SIZE 16
class IBMPC
{
@ -127,8 +124,14 @@ class IBMPC
private:
volatile uint16_t isr_state;
uint8_t timer_start;
ringbuf_t rb;
uint8_t rbuf[RINGBUF_SIZE];
/* ring buffer */
// Size should be power of 2
#define RINGBUF_SIZE 16
uint8_t rb_head;
uint8_t rb_tail;
uint8_t rb_buffer[RINGBUF_SIZE];
const uint8_t clock_bit, data_bit;
const uint8_t clock_mask, data_mask;
@ -237,6 +240,37 @@ class IBMPC
{
EIMSK &= ~clock_mask;
}
/*
* ring buffer
*/
inline int16_t ringbuf_get(void) __attribute__((__always_inline__))
{
if (ringbuf_is_empty()) return -1;
uint8_t data = rb_buffer[rb_tail];
rb_tail++;
rb_tail &= (RINGBUF_SIZE - 1);
return data;
}
inline void ringbuf_put(uint8_t data) __attribute__((__always_inline__))
{
rb_buffer[rb_head] = data;
rb_head++;
rb_head &= (RINGBUF_SIZE - 1);
}
inline bool ringbuf_is_empty(void) __attribute__((__always_inline__))
{
return (rb_head == rb_tail);
}
inline bool ringbuf_is_full(void) __attribute__((__always_inline__))
{
return (((rb_head + 1) & (RINGBUF_SIZE - 1)) == rb_tail);
}
inline void ringbuf_reset(void) __attribute__((__always_inline__))
{
rb_head = 0;
rb_tail = 0;
}
};
#endif