+ OpenGL app loads, runs a firmware and interacts with it.
See the README in examples/ledramp
+ Updated Makefiles & Readme
Streamlined the makefiles, so they use the Makefile.common
rules and so on. Also updated README to bring it up to date.
+ Adding TWI - work in progress
Non working implementation skeleton. Defines a "slave" and a "bus"
And the AVR twi interface that has one of each
Signed-off-by: Michel Pollet <buserror@gmail.com>
F
"./simavr/Makefile"
T
+2 "avr_twi.c"
+F
+"./simavr/sim/avr_twi.c"
+T
+2 "avr_twi.h"
+F
+"./simavr/sim/avr_twi.h"
+T
2 "avr_spi.c"
F
"./simavr/sim/avr_spi.c"
F
"./simavr/sim/avr_uart.h"
T
+2 "sim_twi.c"
+F
+"./simavr/sim/sim_twi.c"
+T
+2 "sim_twi.h"
+F
+"./simavr/sim/sim_twi.h"
+T
2 "sim_core.c"
F
"./simavr/sim/sim_core.c"
F
"./simavr/cores/sim_mega644.c"
F
+T
+1 "examples"
+T
+2 "atmega48_ledramp.c"
+F
+"./examples/board_ledramp/atmega48_ledramp.c"
+T
+2 "ledramp.c"
+F
+"./examples/board_ledramp/ledramp.c"
+T
+2 "button.c"
+F
+"./examples/parts/button.c"
+T
+2 "button.h"
+F
+"./examples/parts/button.h"
+F
F
# tasks
4
# You should have received a copy of the GNU General Public License
# along with simavr. If not, see <http://www.gnu.org/licenses/>.
+CFLAGS += -g --std=gnu99 -O2
+CFLAGS += ${patsubst %,-I%,${subst :, ,${IPATH}}}
+LDFLAGS += -lelf
+
+ifeq (${shell uname}, Darwin)
+AVR_ROOT := "/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/"
+AVR_INC := ${AVR_ROOT}/avr-4/
+AVR := ${AVR_ROOT}/bin/avr-
+else
+AVR_ROOT := /usr/lib/avr
+AVR_INC := ${AVR_ROOT}
+AVR := avr-
+endif
+
%.hex: %.axf
@${AVR}objcopy -j .text -j .data -O ihex ${<} ${@}
# --mcall-prologues
%.axf: %.c
- @echo CC ${<}
+ @echo AVR-CC ${<}
@part=${<} ; part=$${part/_*}; \
${AVR}gcc -Wall -gdwarf-2 -Os -std=gnu99 \
-mmcu=$$part \
-ffunction-sections -fdata-sections \
-Wl,--relax,--gc-sections \
-Wl,--undefined=_mmcu,--section-start=.mmcu=0x910000 \
- -I../include \
+ -I../include -I../../include \
${<} -o ${@}
@${AVR}size ${@}|sed '1d'
+
+OBJ = obj
+
+${OBJ}/%.o: %.c
+ @gcc $(CFLAGS) -MD \
+ $< -c -o $@
+ @echo CC $<
+
+${OBJ}:
+ mkdir -p ${OBJ}
+
+# include the dependency files generated by gcc, if any
+-include ${wildcard ${OBJ}/*.d}
avr-gcc own register definition to simplify creating new targets for supoortted AVR
devices.
-The core was made to be small and compact, and hackable so allow quick protoyping
+The core was made to be small and compact, and hackable so allow quick prototyping
of an AVR project. The simulator loads .elf directly, and there is even a way to
specify simulation parameters directly in the emulated code using an .elf section.
-The status of the project is the core works at about 98% (ie, it works, but there
-is a known bug). The supported IOs are eeprom, IO ports (including pin interupts),
-8 bits timers (well, one of mode of the myriad) and a simple UART that makes
-ÒprintfÓ work.
+The status of the project is the core works fine now. The supported IOs are eeprom,
+IO ports (including pin interupts), 8 bits timers (well, one of mode of the myriad),
+SPI master & slave, and the UART with tx&rx interrupts.
-gdb support is planned next.
+gdb support is implemented and works great (minus watchpoints).
+
+The supported AVR cores are in the simavr/cores directory. It's very simple to
+add new devices if yours is not there.
+
+There is also one example of how to integrate simavr core into your own program in the
+"examples" directory.
+
+(C) 2008-2010, Michel Pollet <buserror@gmail.com>
PREQUISTES:
+ avr-gcc ; tested with 4.3.4 (from debian)
The code rudely assumes the avr-gcc is in /usr/lib/avr/include/...
+ On OSX, the Makefile tries to use the Arduino.app toolchain & headers
+ libelf-dev
BUILD:
+ make
TEST:
-+ ./simavr/simavr tests/atmega88_example.axf
-
-There are no command line options for now.. The simulator recognizes attiny85,
-atmega48,88,168 and atmega644. It's fairly easy to add new cores.
-
-Michel Pollet <buserror@gmail.com>
++ ./simavr/run_avr tests/atmega88_example.axf
--- /dev/null
+
+all:
+ make -C board_ledramp
+
+clean:
+ make -C board_ledramp clean
+
--- /dev/null
+#
+# Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
+#
+# This file is part of simavr.
+#
+# simavr is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# simavr is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with simavr. If not, see <http://www.gnu.org/licenses/>.
+
+board= ledramp
+firm_src = ${wildcard at*${board}.c}
+firmware = ${firm_src:.c=.axf}
+simavr = ../../
+
+IPATH = .
+IPATH += ../parts
+IPATH += ${simavr}/include
+IPATH += ${simavr}/simavr/sim
+
+VPATH = .
+VPATH += ../parts
+
+LDFLAGS += -lglut -lpthread
+
+all: obj ${firmware} ${board}
+
+include ${simavr}/Makefile.common
+
+${board} : ${OBJ}/button.o
+${board} : ${OBJ}/${board}.o
+ gcc -MD ${CFLAGS} -o $@ $^ $(LDFLAGS) ${simavr}/simavr/libsimavr.a
+
+clean:
+ rm -rf obj *.hex *.a *.axf ${board}
--- /dev/null
+
+This contains a sample program to demonstrate the use of simavr
+using 'custom' code, and own "peripherals". It shows how it is
+possible to "hook" code to the AVR pins, and also how to make
+"peripherals" and also hook them up to AVR pins.
+
+The demo will display a running "led ramp" that are the representation
+of the PORTB pins of the mega48.
+
+The mega48 firmware runs a timer and a pin-change interrupt that
+will react to a "button press".
+
+The display uses opengl and "glut" so it should be very portable.
+On most linux you will need "freeglut-dev" package.
+
--- /dev/null
+/*
+ atmega48_ledramp.c
+
+ Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
+
+ This file is part of simavr.
+
+ simavr is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ simavr is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with simavr. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <avr/sleep.h>
+
+// for linker, emulator, and programmer's sake
+#include "avr_mcu_section.h"
+AVR_MCU(F_CPU, "atmega48");
+
+#include <stdio.h>
+/* ------------------------------------------------------------------------- */
+static int uart_putchar(char c, FILE *stream) {
+ if (c == '\n')
+ uart_putchar('\r', stream);
+ loop_until_bit_is_set(UCSR0A, UDRE0);
+ UDR0 = c;
+ return 0;
+}
+
+static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL,
+ _FDEV_SETUP_WRITE);
+
+#define TICK_HZ 64
+
+volatile uint32_t tickCount;
+
+ISR(TIMER2_COMPA_vect) // handler for Output Compare 1 overflow interrupt
+{
+ sei();
+ tickCount++;
+}
+
+void tick_init()
+{
+ /*
+ Timer 2 as RTC
+ */
+ // needs to do that before changing the timer registers
+ // ASYNC timer using a 32k crystal
+ ASSR |= (1 << AS2);
+ TCCR2A = (1 << WGM21);
+ // use CLK/8 prescale value, clear timer/counter on compareA match
+ TCCR2B = (2 << CS20);
+ /* -- MathPad
+ clock=32768
+ prescaler=8
+ hz=64
+ (clock/prescaler/hz)-1:63 -- */
+ OCR2A = 63;
+ TIMSK2 |= (1 << OCIE2A);
+}
+
+volatile uint8_t pressed = 0;
+
+ISR(PCINT1_vect)
+{
+ pressed = (PINC & (1 << PC0)) ? 0 : 1;
+ // wouldn't do that on real hardware, but it's a demo...
+ printf("PCINT1_vect %02x\n", PINC);
+}
+
+int main()
+{
+ DDRB=0xff; // all PORT B output
+ DDRC = 0; // make PORT C input
+ // enable pin change interrupt for PORT C pin 0
+ PCMSK1 |= (1 << PCINT8); // C0
+ PCICR |= (1 << PCIE1);
+
+ stdout = &mystdout;
+
+ tick_init();
+ sei();
+
+ uint8_t mask = 0;
+ for (;;) {
+ mask <<= 1;
+ if (!mask)
+ mask = 1;
+ if (pressed)
+ PORTB = 0xff;
+ else
+ PORTB = mask;
+ sleep_mode();
+ }
+}
+
--- /dev/null
+/*
+ ledramp.c
+
+ Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
+
+ This file is part of simavr.
+
+ simavr is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ simavr is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with simavr. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <GL/glut.h>
+#include <pthread.h>
+
+#include "sim_avr.h"
+#include "avr_ioport.h"
+#include "sim_elf.h"
+#include "sim_gdb.h"
+
+#include "button.h"
+
+button_t button;
+int do_button_press = 0;
+avr_t * avr = NULL;
+uint8_t pin_state = 0; // current port B
+
+float pixsize = 64;
+int window;
+
+/*
+ * called when the AVR change any of the pins on port B
+ * so lets update our buffer
+ */
+void pin_changed_hook(struct avr_irq_t * irq, uint32_t value, void * param)
+{
+ pin_state = (pin_state & ~(1 << irq->irq)) | (value << irq->irq);
+}
+
+void displayCB(void) /* function called whenever redisplay needed */
+{
+ // OpenGL rendering goes here...
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // Set up modelview matrix
+ glMatrixMode(GL_MODELVIEW); // Select modelview matrix
+ glLoadIdentity(); // Start with an identity matrix
+
+ float grid = pixsize;
+ float size = grid * 0.8;
+ glBegin(GL_QUADS);
+ glColor3f(1,0,0);
+
+ for (int di = 0; di < 8; di++) {
+ char on = (pin_state & (1 << di)) != 0;
+ if (on) {
+ float x = (di) * grid;
+ float y = 0; //(si * grid * 8) + (di * grid);
+ glVertex2f(x + size, y + size);
+ glVertex2f(x, y + size);
+ glVertex2f(x, y);
+ glVertex2f(x + size, y);
+ }
+ }
+
+ glEnd();
+ glutSwapBuffers();
+ //glFlush(); /* Complete any pending operations */
+}
+
+void keyCB(unsigned char key, int x, int y) /* called on key press */
+{
+ if (key == 'q')
+ exit(0);
+ static uint8_t buf[64];
+ switch (key) {
+ case 'q':
+ case 0x1f: // escape
+ exit(0);
+ break;
+ case ' ':
+ do_button_press++; // pass the message to the AVR thread
+ break;
+ }
+}
+
+// gl timer. if the pin have changed states, refresh display
+void timerCB(int i)
+{
+ static uint8_t oldstate = 0xff;
+ // restart timer
+ glutTimerFunc(1000/64, timerCB, 0);
+
+ if (oldstate != pin_state) {
+ oldstate = pin_state;
+ glutPostRedisplay();
+ }
+}
+
+static void * avr_run_thread(void * oaram)
+{
+ int b_press = do_button_press;
+
+ while (1) {
+ avr_run(avr);
+ if (do_button_press != b_press) {
+ b_press = do_button_press;
+ printf("Button pressed\n");
+ button_press(&button, 1000000);
+ }
+ }
+}
+
+
+int main(int argc, char *argv[])
+{
+ elf_firmware_t f;
+ const char * fname = "atmega48_ledramp.axf";
+
+ elf_read_firmware(fname, &f);
+
+ printf("firmware %s f=%d mmcu=%s\n", fname, (int)f.mmcu.f_cpu, f.mmcu.name);
+
+ avr = avr_make_mcu_by_name(f.mmcu.name);
+ if (!avr) {
+ fprintf(stderr, "%s: AVR '%s' now known\n", argv[0], f.mmcu.name);
+ exit(1);
+ }
+ avr_init(avr);
+ avr_load_firmware(avr, &f);
+
+ // initialize our 'peripheral'
+ button_init(avr, &button);
+ // "connect" the output irw of the button to the port pin of the AVR
+ avr_connect_irq(
+ button.irq + IRQ_BUTTON_OUT,
+ avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('C'), 0));
+ // 'raise' it, it's a "pullup"
+ avr_raise_irq(button.irq + IRQ_BUTTON_OUT, 1);
+
+ // connect all the pins on port B to our callback
+ for (int i = 0; i < 8; i++)
+ avr_irq_register_notify(
+ avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), i),
+ pin_changed_hook,
+ NULL);
+
+ // even if not setup at startup, activate gdb if crashing
+ avr->gdb_port = 1234;
+ if (0) {
+ //avr->state = cpu_Stopped;
+ avr_gdb_init(avr);
+ }
+
+ printf( "Demo launching: 'LED' bar is PORTB, updated every 1/64s by the AVR\n"
+ " firmware using a timer. If you press 'space' this presses a virtual\n"
+ " 'button' that is hooked to the virtual PORTC pin 0 and will\n"
+ " trigger a 'pin change interrupt' in the AVR core, and will 'invert'\n"
+ " the display.\n"
+ " Press 'q' to quit\n");
+
+ /*
+ * OpenGL init, can be ignored
+ */
+ glutInit(&argc, argv); /* initialize GLUT system */
+
+ glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
+ glutInitWindowSize(8 * pixsize, 1 * pixsize); /* width=400pixels height=500pixels */
+ window = glutCreateWindow("Glut"); /* create window */
+
+ // Set up projection matrix
+ glMatrixMode(GL_PROJECTION); // Select projection matrix
+ glLoadIdentity(); // Start with an identity matrix
+ glOrtho(0, 8 * pixsize, 0, 1 * pixsize, 0, 10);
+ glScalef(1,-1,1);
+ glTranslatef(0, -1 * pixsize, 0);
+
+ glutDisplayFunc(displayCB); /* set window's display callback */
+ glutKeyboardFunc(keyCB); /* set window's key callback */
+ glutTimerFunc(1000 / 24, timerCB, 0);
+
+ // the AVR run on it's own thread. it even allows for debugging!
+ pthread_t run;
+ pthread_create(&run, NULL, avr_run_thread, NULL);
+
+ glutMainLoop();
+}
--- /dev/null
+/*
+ button.c
+
+ This defines a sample for a very simple "peripheral"
+ that can talk to an AVR core.
+ It is in fact a bit more involved than strictly necessary,
+ but is made to demonstrante a few useful features that are
+ easy to use.
+
+ Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
+
+ This file is part of simavr.
+
+ simavr is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ simavr is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with simavr. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "sim_avr.h"
+#include "button.h"
+
+static avr_cycle_count_t button_auto_release(struct avr_t * avr, avr_cycle_count_t when, void * param)
+{
+ button_t * b = (button_t *)param;
+ avr_raise_irq(b->irq + IRQ_BUTTON_OUT, 1);
+ printf("button_auto_release\n");
+ return 0;
+}
+
+/*
+ * button press. set the "pin" to zerok and register a timer
+ * that will reset it in a few usecs
+ */
+void button_press(button_t * b, uint32_t duration_usec)
+{
+ avr_cycle_timer_cancel(b->avr, button_auto_release, b);
+ avr_raise_irq(b->irq + IRQ_BUTTON_OUT, 0);// press
+ // register the auto-release
+ avr_cycle_timer_register_usec(b->avr, duration_usec, button_auto_release, b);
+}
+
+void button_init(struct avr_t *avr, button_t * b)
+{
+ b->irq = avr_alloc_irq(0, IRQ_BUTTON_COUNT);
+ b->avr = avr;
+}
+
--- /dev/null
+/*
+ button.h
+
+ This defines a sample for a very simple "peripheral"
+ that can talk to an AVR core.
+ It is in fact a bit more involved than strictly necessary,
+ but is made to demonstrante a few useful features that are
+ easy to use.
+
+ Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
+
+ This file is part of simavr.
+
+ simavr is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ simavr is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with simavr. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __BUTTON_H__
+#define __BUTTON_H__
+
+#include "sim_irq.h"
+
+enum {
+ IRQ_BUTTON_OUT = 0,
+ IRQ_BUTTON_COUNT
+};
+
+typedef struct button_t {
+ avr_irq_t * irq; // output irq
+ struct avr_t * avr;
+ uint8_t value;
+} button_t;
+
+void button_init(struct avr_t * avr, button_t * b);
+
+void button_press(button_t * b, uint32_t duration_usec);
+#endif /* __BUTTON_H__*/
target = run_avr
-ifeq (${shell uname}, Darwin)
-AVR_ROOT := "/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/avr-4/"
-else
-AVR_ROOT := /usr/lib/avr
-endif
-
-CFLAGS = -g -std=gnu99 -Wall
CFLAGS += -O3 -mfpmath=sse -msse2
cores = ${wildcard cores/*.c}
IPATH += ../include
IPATH += /opt/local/include
-CFLAGS += ${patsubst %,-I%,${subst :, ,${IPATH}}}
LFLAGS = -L/opt/local/lib/
-LDFLAGS += -lelf
all: obj libsimavr.a ${target}
-obj:
- @mkdir -p obj
-
obj/sim_%.o : cores/sim_%.c
@gcc $(CFLAGS) -MD \
- -I${AVR_ROOT}/include/ \
+ -I${AVR_INC}/include/ \
$< -c -o $@
@echo CORE $<
-obj/%.o: %.c
- @gcc $(CFLAGS) -MD \
- $< -c -o $@
- @echo CC $<
+include ../Makefile.common
libsimavr.a : ${cores_o}
libsimavr.a : ${sim_o}
clean:
rm -rf ${target} obj *.a
-# include the dependency files generated by gcc, if any
--include ${wildcard obj/*.d}
-
#include "avr_uart.h"
#include "avr_timer8.h"
#include "avr_spi.h"
+#include "avr_twi.h"
#define _AVR_IO_H_
#define __ASSEMBLER__
avr_uart_t uart0,uart1;
avr_timer8_t timer0,timer2;
avr_spi_t spi;
+ avr_twi_t twi;
} mcu = {
.core = {
.mmcu = "atmega644",
.vector = SPI_STC_vect,
},
},
+
+ .twi = {
+ .disabled = AVR_IO_REGBIT(PRR,PRTWI),
+
+ .r_twcr = TWCR,
+ .r_twsr = TWSR,
+ .r_twbr = TWBR,
+ .r_twdr = TWDR,
+ .r_twar = TWAR,
+ .r_twamr = TWAMR,
+
+ .twen = AVR_IO_REGBIT(TWCR, TWEN),
+ .twea = AVR_IO_REGBIT(TWCR, TWEA),
+ .twsta = AVR_IO_REGBIT(TWCR, TWSTA),
+ .twsto = AVR_IO_REGBIT(TWCR, TWSTO),
+ .twwc = AVR_IO_REGBIT(TWCR, TWWC),
+
+ .twsr = AVR_IO_REGBITS(TWSR, TWS3, 0x1f), // 5 bits
+ .twps = AVR_IO_REGBITS(TWSR, TWPS0, 0x3), // 2 bits
+
+ .twi = {
+ .enable = AVR_IO_REGBIT(TWCR, TWIE),
+ .raised = AVR_IO_REGBIT(TWSR, TWINT),
+ .vector = TWI_vect,
+ },
+ },
+
};
static avr_t * make()
avr_timer8_init(avr, &mcu->timer0);
avr_timer8_init(avr, &mcu->timer2);
avr_spi_init(avr, &mcu->spi);
+ avr_twi_init(avr, &mcu->twi);
}
static void reset(struct avr_t * avr)
avr_timer8_init(avr, &mcu->timer0);
avr_timer8_init(avr, &mcu->timer2);
avr_spi_init(avr, &mcu->spi);
+ avr_twi_init(avr, &mcu->twi);
}
void mx8_reset(struct avr_t * avr)
#include "avr_uart.h"
#include "avr_timer8.h"
#include "avr_spi.h"
+#include "avr_twi.h"
void mx8_init(struct avr_t * avr);
void mx8_reset(struct avr_t * avr);
avr_uart_t uart;
avr_timer8_t timer0,timer2;
avr_spi_t spi;
+ avr_twi_t twi;
};
#ifdef SIM_CORENAME
.vector = SPI_STC_vect,
},
},
+
+ .twi = {
+ .disabled = AVR_IO_REGBIT(PRR,PRTWI),
+
+ .r_twcr = TWCR,
+ .r_twsr = TWSR,
+ .r_twbr = TWBR,
+ .r_twdr = TWDR,
+ .r_twar = TWAR,
+ .r_twamr = TWAMR,
+
+ .twen = AVR_IO_REGBIT(TWCR, TWEN),
+ .twea = AVR_IO_REGBIT(TWCR, TWEA),
+ .twsta = AVR_IO_REGBIT(TWCR, TWSTA),
+ .twsto = AVR_IO_REGBIT(TWCR, TWSTO),
+ .twwc = AVR_IO_REGBIT(TWCR, TWWC),
+
+ .twsr = AVR_IO_REGBITS(TWSR, TWS3, 0x1f), // 5 bits
+ .twps = AVR_IO_REGBITS(TWSR, TWPS0, 0x3), // 2 bits
+
+ .twi = {
+ .enable = AVR_IO_REGBIT(TWCR, TWIE),
+ .raised = AVR_IO_REGBIT(TWSR, TWINT),
+ .vector = TWI_vect,
+ },
+ },
+
};
#endif /* SIM_CORENAME */
--- /dev/null
+/*
+ avr_twi.c
+
+ Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
+
+ This file is part of simavr.
+
+ simavr is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ simavr is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with simavr. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include "avr_twi.h"
+
+static uint8_t avr_twi_read(struct avr_t * avr, avr_io_addr_t addr, void * param)
+{
+ avr_twi_t * p = (avr_twi_t *)param;
+// uint8_t v = p->input_data_register;
+// p->input_data_register = 0;
+// printf("avr_twi_read = %02x\n", v);
+ return 0;
+}
+
+static void avr_twi_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param)
+{
+ avr_twi_t * p = (avr_twi_t *)param;
+#if 0
+ if (addr == p->r_spdr) {
+// printf("avr_twi_write = %02x\n", v);
+ avr_core_watch_write(avr, addr, v);
+
+ if (avr_regbit_get(avr, p->spe)) {
+ // in master mode, any byte is sent as it comes..
+ if (avr_regbit_get(avr, p->mstr)) {
+ avr_raise_irq(p->io.irq + TWI_IRQ_OUTPUT, v);
+ }
+ }
+ }
+#endif
+}
+
+static void avr_twi_irq_input(struct avr_irq_t * irq, uint32_t value, void * param)
+{
+ avr_twi_t * p = (avr_twi_t *)param;
+ avr_t * avr = p->io.avr;
+
+ // check to see if we are enabled
+ if (!avr_regbit_get(avr, p->twen))
+ return;
+#if 0
+ // double buffer the input.. ?
+ p->input_data_register = value;
+ avr_raise_interrupt(avr, &p->twi);
+
+ // if in slave mode,
+ // 'output' the byte only when we received one...
+ if (!avr_regbit_get(avr, p->mstr)) {
+ avr_raise_irq(p->io.irq + TWI_IRQ_OUTPUT, avr->data[p->r_spdr]);
+ }
+#endif
+}
+
+static int twi_slave_has_address(struct twi_slave_t* p, uint8_t address)
+{
+ return 0;
+}
+
+ // handle start conditionto address+w, restart means "stop" wasn't called
+static int twi_slave_start(struct twi_slave_t* p, uint8_t address, int restart)
+{
+ return 0;
+}
+
+ // handle a data write, after a (re)start
+static int twi_slave_write(struct twi_slave_t* p, uint8_t v)
+{
+ return 0;
+}
+
+ // handle a data read, after a (re)start
+static uint8_t twi_slave_read(struct twi_slave_t* p)
+{
+ return 0;
+}
+
+ // stop condition detected
+static void twi_slave_stop(struct twi_slave_t* p)
+{
+}
+
+static twi_slave_t slave_driver = {
+ .has_address = twi_slave_has_address,
+ .start = twi_slave_start,
+ .stop = twi_slave_stop,
+ .write = twi_slave_write,
+ .read = twi_slave_read
+};
+
+void avr_twi_reset(struct avr_io_t *io)
+{
+ avr_twi_t * p = (avr_twi_t *)io;
+ //avr_irq_register_notify(p->io.irq + TWI_IRQ_INPUT, avr_twi_irq_input, p);
+}
+
+static avr_io_t _io = {
+ .kind = "twi",
+ .reset = avr_twi_reset,
+};
+
+void avr_twi_init(avr_t * avr, avr_twi_t * p)
+{
+ p->io = _io;
+ avr_register_io(avr, &p->io);
+ avr_register_vector(avr, &p->twi);
+ p->slave = slave_driver; // get default callbacks
+ twi_slave_init(&p->slave, p);
+ twi_bus_init(&p->bus);
+
+ printf("%s TWI%c init\n", __FUNCTION__, p->name);
+
+ // allocate this module's IRQ
+ p->io.irq_count = TWI_IRQ_COUNT;
+ p->io.irq = avr_alloc_irq(0, p->io.irq_count);
+ p->io.irq_ioctl_get = AVR_IOCTL_TWI_GETIRQ(p->name);
+
+ avr_register_io_write(avr, p->r_twdr, avr_twi_write, p);
+ avr_register_io_read(avr, p->r_twdr, avr_twi_read, p);
+}
+
--- /dev/null
+/*
+ avr_twi.h
+
+ Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
+
+ This file is part of simavr.
+
+ simavr is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ simavr is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with simavr. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef AVR_TWI_H_
+#define AVR_TWI_H_
+
+#include "sim_avr.h"
+
+#include "sim_twi.h"
+
+enum {
+ TWI_IRQ_INPUT = 0,
+ TWI_IRQ_OUTPUT,
+ TWI_IRQ_COUNT
+};
+
+
+// add port number to get the real IRQ
+#define AVR_IOCTL_TWI_GETIRQ(_name) AVR_IOCTL_DEF('t','w','i',(_name))
+// return a pointer to the slave structure related to this TWI port
+#define AVR_IOCTL_TWI_GETSLAVE(_name) AVR_IOCTL_DEF('t','w','s',(_name))
+// retutn this twi interface "master" bus
+#define AVR_IOCTL_TWI_GETBUS(_name) AVR_IOCTL_DEF('t','w','b',(_name))
+
+typedef struct avr_twi_t {
+ avr_io_t io;
+ char name;
+
+ twi_slave_t slave; // when we are a slave, to be attached to some bus
+ twi_bus_t bus; // when we are a master, to attach slaves to
+
+ avr_regbit_t disabled; // bit in the PRR
+
+ avr_io_addr_t r_twbr; // bit rate register
+ avr_io_addr_t r_twcr; // control register
+ avr_io_addr_t r_twsr; // status register
+ avr_io_addr_t r_twar; // address register (slave)
+ avr_io_addr_t r_twamr; // address mask register
+ avr_io_addr_t r_twdr; // data register
+
+ avr_regbit_t twen; // twi enable bit
+ avr_regbit_t twea; // enabke acknowledge bit
+ avr_regbit_t twsta; // start condition
+ avr_regbit_t twsto; // stop condition
+ avr_regbit_t twwc; // write collision
+
+ avr_regbit_t twsr; // status registers, (5 bits)
+ avr_regbit_t twps; // prescaler bits (2 bits)
+
+ avr_int_vector_t twi; // spi interrupt
+} avr_twi_t;
+
+void avr_twi_init(avr_t * avr, avr_twi_t * port);
+
+#endif /* AVR_TWI_H_ */
--- /dev/null
+/*
+ sim_twi.c
+
+ Internal TWI/i2c slave/master subsystem
+
+ Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
+
+ This file is part of simavr.
+
+ simavr is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ simavr is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with simavr. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include "sim_twi.h"
+
+void twi_bus_init(twi_bus_t * bus)
+{
+}
+
+void twi_bus_attach(twi_bus_t * bus, twi_slave_t * slave)
+{
+ twi_slave_detach(slave);
+ slave->bus = bus;
+ slave->next = bus->slave;
+ bus->slave = slave;
+}
+
+int twi_bus_start(twi_bus_t * bus, uint8_t address)
+{
+ // if we already have a peer, check to see if it's
+ // still matching, if so, skip the lookup
+ if (bus->peer && twi_slave_match(bus->peer, address))
+ return bus->peer->start(bus->peer, address, 1);
+
+ bus->peer = NULL;
+ twi_slave_t *s = bus->slave;
+ while (s) {
+ if (twi_slave_match(s, address)) {
+ if (s->start(s, address, 0)) {
+ bus->peer = s;
+ s->byte_index = 0;
+ return 1;
+ }
+ }
+ s = s->next;
+ }
+ return 0;
+}
+
+void twi_bus_stop(twi_bus_t * bus)
+{
+ if (bus->peer && bus->peer->stop)
+ bus->peer->stop(bus->peer);
+ bus->peer = NULL;
+}
+
+int twi_bus_write(twi_bus_t * bus, uint8_t data)
+{
+ if (!bus->peer || !bus->peer->write)
+ return 0;
+
+ int res = bus->peer->write(bus->peer, data);
+ if (bus->peer)
+ bus->peer->byte_index++;
+ return res;
+}
+
+uint8_t twi_bus_read(twi_bus_t * bus)
+{
+ if (!bus->peer || !bus->peer->read)
+ return 0;
+
+ uint8_t res = bus->peer->read(bus->peer);
+ if (bus->peer)
+ bus->peer->byte_index++;
+ return res;
+}
+
+void twi_slave_init(twi_slave_t * slave, void * param)
+{
+ slave->param = param;
+}
+
+void twi_slave_detach(twi_slave_t * slave)
+{
+ if (!slave || !slave->bus)
+ return;
+ twi_slave_t *s = slave->bus->slave;
+ while (s) {
+ if (s->next == slave) {
+ // clear that, too
+ if (slave->bus->peer == slave)
+ slave->bus->peer = NULL;
+
+ s->next = slave->next;
+ slave->next = NULL;
+ slave->bus = NULL;
+ return;
+ }
+ s = s->next;
+ }
+}
+
+int twi_slave_match(twi_slave_t * slave, uint8_t address)
+{
+ if (slave->has_address)
+ return slave->has_address(slave, address);
+ return (address & ~1) == (slave->address & ~1);
+}
+
--- /dev/null
+/*
+ sim_twi.h
+
+ Internal TWI/i2c slave/master subsystem
+
+ You can have a "bus" to talk to a bunch of "slaves"
+
+ Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
+
+ This file is part of simavr.
+
+ simavr is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ simavr is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with simavr. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef SIM_TWI_H_
+#define SIM_TWI_H_
+
+#include <stdint.h>
+
+typedef struct twi_slave_t {
+ struct twi_bus_t * bus; // bus we are attached to
+ struct twi_slave_t * next; // daisy chain on the bus
+
+ void * param; // module parameter
+ uint8_t address; // slave address (lowest bit is not used, it's for the W bit)
+ int byte_index; // byte index in the transaction (since last start, restart)
+
+ // return non-zero if this slave address is handled by this slave
+ // if NULL, the "address" field is used instead. If this function
+ // is present, 'address' field is not used.
+ int (*has_address)(struct twi_slave_t* p, uint8_t address); // optional
+
+ // handle start conditionto address+w, restart means "stop" wasn't called
+ int (*start)(struct twi_slave_t* p, uint8_t address, int restart);
+ // handle a data write, after a (re)start
+ int (*write)(struct twi_slave_t* p, uint8_t v);
+ // handle a data read, after a (re)start
+ uint8_t (*read)(struct twi_slave_t* p);
+ // stop condition detected
+ void (*stop)(struct twi_slave_t* p);
+} twi_slave_t;
+
+
+typedef struct twi_bus_t {
+ struct twi_slave_t * slave; // daisy chain on the bus
+
+ struct twi_slave_t * peer; // during a transaction, this is the selected slave
+} twi_bus_t;
+
+void twi_bus_init(twi_bus_t * bus);
+int twi_bus_start(twi_bus_t * bus, uint8_t address);
+int twi_bus_write(twi_bus_t * bus, uint8_t data);
+uint8_t twi_bus_read(twi_bus_t * bus);
+void twi_bus_stop(twi_bus_t * bus);
+
+void twi_slave_init(twi_slave_t * slave, void * param);
+void twi_slave_detach(twi_slave_t * slave);
+int twi_slave_match(twi_slave_t * slave, uint8_t address);
+
+#endif /* SIM_TWI_H_ */
# You should have received a copy of the GNU General Public License
# along with simavr. If not, see <http://www.gnu.org/licenses/>.
-ifeq (${shell uname}, Darwin)
-AVR_ROOT := "/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/"
-else
-AVR_ROOT :=
-endif
-AVR := ${AVR_ROOT}avr-
SHELL = /bin/bash