3 Commits c146508c3a ... 7072f417e8

Author SHA1 Message Date
  Michael Buesch 7072f417e8 tests/fake: Add emulation layer to all registers 5 years ago
  Michael Buesch 1b55a2465a debug: Always enable the UART in simulation mode 5 years ago
  Michael Buesch 94a132b9f9 tests: Compile tests with c++ compiler 5 years ago

+ 12 - 1
firmware/debug_uart.c

@@ -171,8 +171,19 @@ void debug_report_int8(const char __flash *prefix,
 
 void debug_enable(bool enable)
 {
+	bool display_en;
+
+#ifdef SIMULATOR
+	enable = true;
+	display_en = true;
+#else
+	/* The display and the UART share pins.
+	 * Disable the display, if UART is enabled. */
+	display_en = !enable;
+#endif
+
 	debug_enabled = enable;
-	display_enable(!enable);
+	display_enable(display_en);
 	if (enable) {
 		debug_uart_enable();
 		debug_uart_tx_string(to_memx(PSTR("\r\nst\r\n")));

+ 6 - 3
firmware/tests/Makefile

@@ -1,10 +1,13 @@
 CPPFLAGS	:= -I.. -Ifake -DF_CPU=8000000UL \
 		   -DTESTSUITE=1 -D_DEFAULT_SOURCE
-CFLAGS		:= -std=c11 -g -O2 -Wall -Wextra -Wno-unused-parameter -Wswitch-enum \
+
+CXXFLAGS	:= -std=c++17 -g -O2 -Wall -Wextra -Wno-unused-parameter -Wswitch-enum \
 		   -Wsuggest-attribute=noreturn -Wundef -Wpointer-arith \
 		   -Wcast-qual -Wlogical-op -Wshadow -Wconversion \
 		   -Wno-shift-negative-value
 
+CFLAGS		:=
+
 LDFLAGS		:=
 
 TESTS		:= test_common \
@@ -16,10 +19,10 @@ TESTS		:= test_common \
 TEST_BINS	:= $(foreach t,$(TESTS),$(t).run)
 
 %.o: %.c test.h
-	$(CC) -o $@ -c $(CPPFLAGS) $(CFLAGS) $<
+	$(CXX) -o $@ -c $(CPPFLAGS) $(CFLAGS) $<
 
 test_%.run: test_%.o fake/fake.o
-	$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $(LDFLAGS) $^
+	$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ $(LDFLAGS) $^
 
 all: $(TEST_BINS)
 	./test_common.run

+ 1 - 1
firmware/tests/fake/avr/eeprom.h

@@ -2,7 +2,7 @@
 #define FAKE_EEPROM_H_
 
 
-#define EEMEM
+#define EEMEM			__attribute__((section("eeprom")))
 
 #define eeprom_is_ready()	1
 #define eeprom_busy_wait()	do { } while (!eeprom_is_ready())

+ 201 - 56
firmware/tests/fake/avr/io.h

@@ -3,14 +3,125 @@
 
 #include <endian.h>
 #include <stdint.h>
+#include <mutex>
+
+
+template <typename T> class FakeIO
+{
+public:
+	FakeIO()
+		: m_read_hook(NULL)
+		, m_read_hook_running(false)
+		, m_write_hook(NULL)
+		, m_write_hook_running(false)
+	{
+	}
+	virtual ~FakeIO()
+	{
+	}
+
+	FakeIO & operator=(const T &other)
+	{
+		std::lock_guard<std::recursive_mutex> locker(m_mutex);
+
+		T prev_value = m_reg;
+		m_reg = other;
+		call_write_hook(prev_value);
+
+		return *this;
+	}
+
+	FakeIO & operator|=(const T &other)
+	{
+		std::lock_guard<std::recursive_mutex> locker(m_mutex);
+
+		T prev_value = m_reg;
+		m_reg |= other;
+		call_write_hook(prev_value);
+
+		return *this;
+	}
+
+	FakeIO & operator&=(const T &other)
+	{
+		std::lock_guard<std::recursive_mutex> locker(m_mutex);
+
+		T prev_value = m_reg;
+		m_reg &= other;
+		call_write_hook(prev_value);
+
+		return *this;
+	}
+
+	operator T()
+	{
+		std::lock_guard<std::recursive_mutex> locker(m_mutex);
+
+		call_read_hook();
+		return m_reg;
+	}
+
+	volatile uint8_t * low_byte()
+	{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+		return reinterpret_cast<volatile uint8_t *>(&m_reg) + 0;
+#else
+		return reinterpret_cast<volatile uint8_t *>(&m_reg) + 1;
+#endif
+	}
 
-
-#define _SFR_ADDR(x) (&(x))
-#define _MMIO_BYTE(x) (*(uint8_t *)(x))
-typedef volatile uint8_t * sfr_addr_t;
-#define sfr_addr_t sfr_addr_t
-
-extern volatile uint8_t MCUCSR;
+	volatile uint8_t * high_byte()
+	{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+		return reinterpret_cast<volatile uint8_t *>(&m_reg) + 1;
+#else
+		return reinterpret_cast<volatile uint8_t *>(&m_reg) + 0;
+#endif
+	}
+
+	void set_read_hook(void (*read_hook)(FakeIO<T> &io))
+	{
+		m_read_hook = read_hook;
+	}
+	void set_write_hook(void (*write_hook)(FakeIO<T> &io, T prev_value))
+	{
+		m_write_hook = write_hook;
+	}
+
+protected:
+	void call_read_hook()
+	{
+		if (m_read_hook && !m_read_hook_running) {
+			m_read_hook_running = true;
+			m_read_hook(*this);
+			m_read_hook_running = false;
+		}
+	}
+	void call_write_hook(T prev_value)
+	{
+		if (m_write_hook && !m_write_hook_running) {
+			m_write_hook_running = true;
+			m_write_hook(*this, prev_value);
+			m_write_hook_running = false;
+		}
+	}
+
+protected:
+	std::recursive_mutex m_mutex;
+	volatile T m_reg;
+	void (*m_read_hook)(FakeIO<T> &io);
+	bool m_read_hook_running;
+	void (*m_write_hook)(FakeIO<T> &io, T prev_value);
+	bool m_write_hook_running;
+};
+
+
+#define _SFR_ADDR(x)		(static_cast<void *>(&(x)))
+#define _MMIO_BYTE(x)		(*(static_cast<FakeIO<uint8_t> *>(x)))
+typedef void *			sfr_addr_t;
+#define sfr_addr_t		sfr_addr_t
+
+extern FakeIO<uint8_t> MCUCSR;
 #define MCUCSR	MCUCSR
 #define MCUSR	MCUCSR
 
@@ -22,7 +133,7 @@ extern volatile uint8_t MCUCSR;
 #define PB5	5
 #define PB6	6
 #define PB7	7
-extern volatile uint8_t PORTB;
+extern FakeIO<uint8_t> PORTB;
 #define PORTB	PORTB
 #define PC0	0
 #define PC1	1
@@ -32,7 +143,7 @@ extern volatile uint8_t PORTB;
 #define PC5	5
 #define PC6	6
 #define PC7	7
-extern volatile uint8_t PORTC;
+extern FakeIO<uint8_t> PORTC;
 #define PORTC	PORTC
 #define PD0	0
 #define PD1	1
@@ -42,7 +153,7 @@ extern volatile uint8_t PORTC;
 #define PD5	5
 #define PD6	6
 #define PD7	7
-extern volatile uint8_t PORTD;
+extern FakeIO<uint8_t> PORTD;
 #define PORTD	PORTD
 #define DDB0	0
 #define DDB1	1
@@ -52,7 +163,7 @@ extern volatile uint8_t PORTD;
 #define DDB5	5
 #define DDB6	6
 #define DDB7	7
-extern volatile uint8_t DDRB;
+extern FakeIO<uint8_t> DDRB;
 #define DDRB	DDRB
 #define DDC0	0
 #define DDC1	1
@@ -62,7 +173,7 @@ extern volatile uint8_t DDRB;
 #define DDC5	5
 #define DDC6	6
 #define DDC7	7
-extern volatile uint8_t DDRC;
+extern FakeIO<uint8_t> DDRC;
 #define DDRC	DDRC
 #define DDD0	0
 #define DDD1	1
@@ -72,7 +183,7 @@ extern volatile uint8_t DDRC;
 #define DDD5	5
 #define DDD6	6
 #define DDD7	7
-extern volatile uint8_t DDRD;
+extern FakeIO<uint8_t> DDRD;
 #define DDRD	DDRD
 #define PINB0	0
 #define PINB1	1
@@ -82,7 +193,7 @@ extern volatile uint8_t DDRD;
 #define PINB5	5
 #define PINB6	6
 #define PINB7	7
-extern volatile uint8_t PINB;
+extern FakeIO<uint8_t> PINB;
 #define PINB	PINB
 #define PINC0	0
 #define PINC1	1
@@ -92,7 +203,7 @@ extern volatile uint8_t PINB;
 #define PINC5	5
 #define PINC6	6
 #define PINC7	7
-extern volatile uint8_t PINC;
+extern FakeIO<uint8_t> PINC;
 #define PINC	PINC
 #define PIND0	0
 #define PIND1	1
@@ -102,33 +213,33 @@ extern volatile uint8_t PINC;
 #define PIND5	5
 #define PIND6	6
 #define PIND7	7
-extern volatile uint8_t PIND;
+extern FakeIO<uint8_t> PIND;
 #define PIND	PIND
 
 #define OCIE0B	2
 #define OCIE0A	1
 #define TOIE0	0
-extern volatile uint8_t TIMSK0;
+extern FakeIO<uint8_t> TIMSK0;
 #define TIMSK0	TIMSK0
 
 #define OCF0B	2
 #define OCF0A	1
 #define TOV0	0
-extern volatile uint8_t TIFR0;
+extern FakeIO<uint8_t> TIFR0;
 #define TIFR0	TIFR0
 
 #define ICIE1	5
 #define OCIE1B	2
 #define OCIE1A	1
 #define TOIE1	0
-extern volatile uint8_t TIMSK1;
+extern FakeIO<uint8_t> TIMSK1;
 #define TIMSK1	TIMSK1
 
 #define ICF1	5
 #define OCF1B	2
 #define OCF1A	1
 #define TOV1	0
-extern volatile uint8_t TIFR1;
+extern FakeIO<uint8_t> TIFR1;
 #define TIFR1	TIFR1
 
 #define SREG_C	0
@@ -139,7 +250,7 @@ extern volatile uint8_t TIFR1;
 #define SREG_H	5
 #define SREG_T	6
 #define SREG_I	7
-extern volatile uint8_t SREG;
+extern FakeIO<uint8_t> SREG;
 #define SREG	SREG
 
 #define COM0A1	7
@@ -171,40 +282,40 @@ extern volatile uint8_t SREG;
 #define FOC1A	7
 #define FOC1B	6
 
-extern volatile uint8_t OCR0A;
+extern FakeIO<uint8_t> OCR0A;
 #define OCR0A	OCR0A
 
-extern volatile uint8_t OCR0B;
+extern FakeIO<uint8_t> OCR0B;
 #define OCR0B	OCR0B
 
-extern volatile uint8_t TCNT0;
+extern FakeIO<uint8_t> TCNT0;
 #define TCNT0	TCNT0
 
-extern volatile uint8_t TCCR0A;
+extern FakeIO<uint8_t> TCCR0A;
 #define TCCR0A	TCCR0A
 
-extern volatile uint8_t TCCR0B;
+extern FakeIO<uint8_t> TCCR0B;
 #define TCCR0B	TCCR0B
 
-extern volatile uint16_t OCR1A;
+extern FakeIO<uint16_t> OCR1A;
 #define OCR1A	OCR1A
 
-extern volatile uint16_t OCR1B;
+extern FakeIO<uint16_t> OCR1B;
 #define OCR1B	OCR1B
 
-extern volatile uint16_t ICR1;
+extern FakeIO<uint16_t> ICR1;
 #define ICR1	ICR1
 
-extern volatile uint8_t TCNT1;
+extern FakeIO<uint8_t> TCNT1;
 #define TCNT1	TCNT1
 
-extern volatile uint8_t TCCR1A;
+extern FakeIO<uint8_t> TCCR1A;
 #define TCCR1A	TCCR1A
 
-extern volatile uint8_t TCCR1B;
+extern FakeIO<uint8_t> TCCR1B;
 #define TCCR1B	TCCR1B
 
-extern volatile uint8_t TCCR1C;
+extern FakeIO<uint8_t> TCCR1C;
 #define TCCR1C	TCCR1C
 
 
@@ -214,35 +325,25 @@ extern volatile uint8_t TCCR1C;
 #define EEMPE	2
 #define EEPE	1
 #define EERE	0
-extern volatile uint8_t EECR;
+extern FakeIO<uint8_t> EECR;
 #define EECR	EECR
 
-extern volatile uint8_t EEDR;
+extern FakeIO<uint8_t> EEDR;
 #define EEDR	EEDR
 
-extern volatile uint16_t EEAR;
+typedef uintptr_t ee_addr_t;
+#define ee_addr_t ee_addr_t
+extern FakeIO<ee_addr_t> EEAR;
 #define EEAR	EEAR
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-# define EEARL	(*(((uint8_t *)&EEAR) + 0))
-# define EEARH	(*(((uint8_t *)&EEAR) + 1))
-#else
-# define ADCL	(*(((uint8_t *)&EEAR) + 1))
-# define ADCH	(*(((uint8_t *)&EEAR) + 0))
-#endif
 
 #define E2END	0x3FF
 
 
-extern volatile uint16_t ADC;
+extern FakeIO<uint16_t> ADC;
 #define ADC	ADC
 #define ADCW	ADC
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-# define ADCL	(*(((uint8_t *)&ADC) + 0))
-# define ADCH	(*(((uint8_t *)&ADC) + 1))
-#else
-# define ADCL	(*(((uint8_t *)&ADC) + 1))
-# define ADCH	(*(((uint8_t *)&ADC) + 0))
-#endif
+#define ADCL	(*(ADC.low_byte()))
+#define ADCH	(*(ADC.high_byte()))
 
 #define ADEN	7
 #define ADSC	6
@@ -252,14 +353,14 @@ extern volatile uint16_t ADC;
 #define ADPS2	2
 #define ADPS1	1
 #define ADPS0	0
-extern volatile uint8_t ADCSRA;
+extern FakeIO<uint8_t> ADCSRA;
 #define ADCSRA	ADCSRA
 
 #define ACME	6
 #define ADTS2	2
 #define ADTS1	1
 #define ADTS0	0
-extern volatile uint8_t ADCSRB;
+extern FakeIO<uint8_t> ADCSRB;
 #define ADCSRB	ADCSRB
 
 #define REFS1	7
@@ -269,7 +370,7 @@ extern volatile uint8_t ADCSRB;
 #define MUX2	2
 #define MUX1	1
 #define MUX0	0
-extern volatile uint8_t ADMUX;
+extern FakeIO<uint8_t> ADMUX;
 #define ADMUX	ADMUX
 
 #define ADC5D	5
@@ -278,13 +379,57 @@ extern volatile uint8_t ADMUX;
 #define ADC2D	2
 #define ADC1D	1
 #define ADC0D	0
-extern volatile uint8_t DIDR0;
+extern FakeIO<uint8_t> DIDR0;
 #define DIDR0	DIDR0
 
 #define AIN1D	1
 #define AIN0D	0
-extern volatile uint8_t DIDR1;
+extern FakeIO<uint8_t> DIDR1;
 #define DIDR1	DIDR1
 
 
+#define RXC0	7
+#define TXC0	6
+#define UDRE0	5
+#define FE0	4
+#define DOR0	3
+#define UPE0	2
+#define U2X0	1
+#define MPCM0	0
+extern FakeIO<uint8_t> UCSR0A;
+#define UCSR0A	UCSR0A
+
+#define RXCIE0	7
+#define TXCIE0	6
+#define UDRIE0	5
+#define RXEN0	4
+#define TXEN0	3
+#define UCSZ02	2
+#define RXB80	1
+#define TXB80	0
+extern FakeIO<uint8_t> UCSR0B;
+#define UCSR0B	UCSR0B
+
+#define UMSEL01	7
+#define UMSEL00	6
+#define UPM01	5
+#define UPM00	4
+#define USBS0	3
+#define UCSZ01	2
+#define UDORD0	2
+#define UCSZ00	1
+#define UCPHA0	1
+#define UCPOL0	0
+extern FakeIO<uint8_t> UCSR0C;
+#define UCSR0C	UCSR0C
+
+extern FakeIO<uint16_t> UBRR0;
+#define UBRR0	UBRR0
+#define UBRR0L	(*(UBRR0.low_byte()))
+#define UBRR0H	(*(UBRR0.high_byte()))
+
+extern FakeIO<uint8_t> UDR0;
+#define UDR0	UDR0
+
+
 #endif /* FAKE_IO_H_ */

+ 48 - 42
firmware/tests/fake/fake.c

@@ -1,44 +1,50 @@
 #include <avr/io.h>
 
-volatile uint8_t MCUCSR;
-
-volatile uint8_t PORTB;
-volatile uint8_t PORTC;
-volatile uint8_t PORTD;
-volatile uint8_t DDRB;
-volatile uint8_t DDRC;
-volatile uint8_t DDRD;
-volatile uint8_t PINB;
-volatile uint8_t PINC;
-volatile uint8_t PIND;
-
-volatile uint8_t TIMSK0;
-volatile uint8_t TIFR0;
-volatile uint8_t TIMSK1;
-volatile uint8_t TIFR1;
-
-volatile uint8_t SREG;
-
-volatile uint8_t OCR0A;
-volatile uint8_t OCR0B;
-volatile uint8_t TCNT0;
-volatile uint8_t TCCR0A;
-volatile uint8_t TCCR0B;
-volatile uint16_t OCR1A;
-volatile uint16_t OCR1B;
-volatile uint16_t ICR1;
-volatile uint8_t TCNT1;
-volatile uint8_t TCCR1A;
-volatile uint8_t TCCR1B;
-volatile uint8_t TCCR1C;
-
-volatile uint16_t ADC;
-volatile uint8_t ADCSRA;
-volatile uint8_t ADCSRB;
-volatile uint8_t ADMUX;
-volatile uint8_t DIDR0;
-volatile uint8_t DIDR1;
-
-volatile uint8_t EECR;
-volatile uint8_t EEDR;
-volatile uint16_t EEAR;
+FakeIO<uint8_t> MCUCSR;
+
+FakeIO<uint8_t> PORTB;
+FakeIO<uint8_t> PORTC;
+FakeIO<uint8_t> PORTD;
+FakeIO<uint8_t> DDRB;
+FakeIO<uint8_t> DDRC;
+FakeIO<uint8_t> DDRD;
+FakeIO<uint8_t> PINB;
+FakeIO<uint8_t> PINC;
+FakeIO<uint8_t> PIND;
+
+FakeIO<uint8_t> TIMSK0;
+FakeIO<uint8_t> TIFR0;
+FakeIO<uint8_t> TIMSK1;
+FakeIO<uint8_t> TIFR1;
+
+FakeIO<uint8_t> SREG;
+
+FakeIO<uint8_t> OCR0A;
+FakeIO<uint8_t> OCR0B;
+FakeIO<uint8_t> TCNT0;
+FakeIO<uint8_t> TCCR0A;
+FakeIO<uint8_t> TCCR0B;
+FakeIO<uint16_t> OCR1A;
+FakeIO<uint16_t> OCR1B;
+FakeIO<uint16_t> ICR1;
+FakeIO<uint8_t> TCNT1;
+FakeIO<uint8_t> TCCR1A;
+FakeIO<uint8_t> TCCR1B;
+FakeIO<uint8_t> TCCR1C;
+
+FakeIO<uint16_t> ADC;
+FakeIO<uint8_t> ADCSRA;
+FakeIO<uint8_t> ADCSRB;
+FakeIO<uint8_t> ADMUX;
+FakeIO<uint8_t> DIDR0;
+FakeIO<uint8_t> DIDR1;
+
+FakeIO<uint8_t> EECR;
+FakeIO<uint8_t> EEDR;
+FakeIO<ee_addr_t> EEAR;
+
+FakeIO<uint8_t> UCSR0A;
+FakeIO<uint8_t> UCSR0B;
+FakeIO<uint8_t> UCSR0C;
+FakeIO<uint16_t> UBRR0;
+FakeIO<uint8_t> UDR0;

+ 30 - 0
firmware/tests/fake/fake.h

@@ -1,5 +1,35 @@
+#ifndef FAKE_H_
+#define FAKE_H_
+
 #include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
 
 /* This __(u)int24 is 32 bits wide. This might cause problems. */
 typedef uint32_t __uint24;
 typedef int32_t __int24;
+
+static inline char *utoa(unsigned int val, char *s, int radix)
+{
+	if (radix == 16) {
+		sprintf(s, "%X", val);
+	} else {
+		fprintf(stderr, "utoa: Unsupported radix %d\n", radix);
+		abort();
+	}
+	return s;
+}
+
+static inline char *ltoa(long val, char *s, int radix)
+{
+	if (radix == 10) {
+		sprintf(s, "%ld", val);
+	} else {
+		fprintf(stderr, "ltoa: Unsupported radix %d\n", radix);
+		abort();
+	}
+	return s;
+}
+
+#endif /* FAKE_H_ */

+ 14 - 15
firmware/tests/fake/util/delay.h

@@ -7,35 +7,34 @@
 #include <math.h>
 #include <stdio.h>
 
-static inline void _msleep_(unsigned int msecs)
+
+static inline void _usleep__(uint64_t us)
 {
 	int err;
-	struct timespec time;
+	struct timespec tv;
 
-	time.tv_sec = 0;
-	while (msecs >= 1000) {
-		time.tv_sec++;
-		msecs -= 1000;
+	tv.tv_sec = 0;
+	while (us >= 1000000u) {
+		tv.tv_sec++;
+		us -= 1000000u;
 	}
-	time.tv_nsec = msecs;
-	time.tv_nsec *= 1000000;
+	tv.tv_nsec = (int64_t)us * 1000;
 	do {
-		err = nanosleep(&time, &time);
+		err = nanosleep(&tv, &tv);
 	} while (err && errno == EINTR);
-	if (err) {
-		fprintf(stderr, "nanosleep() failed with: %s\n",
-			strerror(errno));
-	}
+	if (err)
+		perror("nanosleep()");
 }
 
 static inline void _delay_ms(double ms)
 {
-	_msleep_((unsigned int)ceil(ms));
+	_usleep__((uint64_t)ceil(ms * 1000.0));
 }
 
 static inline void _delay_us(double us)
 {
-	_msleep_(1);
+	_usleep__((uint64_t)ceil(us));
 }
 
+
 #endif /* FAKE_DELAY_H_ */