Commit 0bfce45007c162fa3f98f4369f7069f3da372502
authorMichel Pollet <buserror@gmail.com>
Mon, 7 Dec 2009 19:45:17 +0000 (19:45 +0000)
committerMichel Pollet <buserror@gmail.com>
Mon, 7 Dec 2009 19:45:17 +0000 (19:45 +0000)
+ 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>
19 files changed:
.simavr.jcc
Makefile.common
README
examples/Makefile [new file with mode: 0644]
examples/board_ledramp/Makefile [new file with mode: 0644]
examples/board_ledramp/README [new file with mode: 0644]
examples/board_ledramp/atmega48_ledramp.c [new file with mode: 0644]
examples/board_ledramp/ledramp.c [new file with mode: 0644]
examples/parts/button.c [new file with mode: 0644]
examples/parts/button.h [new file with mode: 0644]
simavr/Makefile
simavr/cores/sim_mega644.c
simavr/cores/sim_megax8.c
simavr/cores/sim_megax8.h
simavr/sim/avr_twi.c [new file with mode: 0644]
simavr/sim/avr_twi.h [new file with mode: 0644]
simavr/sim/sim_twi.c [new file with mode: 0644]
simavr/sim/sim_twi.h [new file with mode: 0644]
tests/Makefile

index d7a4a412986e8ce21c85e1e61a93f0d3680f0dd7..b8d106c6f076f70a7eaea48d93ae74778c58e93c 100644 (file)
@@ -8,6 +8,14 @@ T
 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"
@@ -48,6 +56,14 @@ T
 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"
@@ -166,6 +182,25 @@ T
 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
index 1f89b04dd1f759b70191a4ae49c1ff778d770e57..77b1ad3fe6c76cfec61c66815b8790157b9c2e29 100644 (file)
 #      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 ${<} ${@}
 
@@ -34,7 +48,7 @@
 
 # --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}
diff --git a/README b/README
index 7aaa72fd6f08420e8e54e25c0d1fe64a6662e96d..185162bb953bec3a6548c2e012e182fcfa9e58d6 100644 (file)
--- a/README
+++ b/README
@@ -7,29 +7,32 @@ simavr is a new AVR simulator for linux, or any platform that uses avr-gcc. It u
 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
diff --git a/examples/Makefile b/examples/Makefile
new file mode 100644 (file)
index 0000000..e9ef6c5
--- /dev/null
@@ -0,0 +1,7 @@
+
+all:
+       make -C board_ledramp
+
+clean:
+       make -C board_ledramp clean
+
diff --git a/examples/board_ledramp/Makefile b/examples/board_ledramp/Makefile
new file mode 100644 (file)
index 0000000..18238ab
--- /dev/null
@@ -0,0 +1,43 @@
+# 
+#      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}
diff --git a/examples/board_ledramp/README b/examples/board_ledramp/README
new file mode 100644 (file)
index 0000000..d701308
--- /dev/null
@@ -0,0 +1,15 @@
+
+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.
+
diff --git a/examples/board_ledramp/atmega48_ledramp.c b/examples/board_ledramp/atmega48_ledramp.c
new file mode 100644 (file)
index 0000000..9dba9b7
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+       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();
+       }       
+}
+
diff --git a/examples/board_ledramp/ledramp.c b/examples/board_ledramp/ledramp.c
new file mode 100644 (file)
index 0000000..78ec0c7
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+       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();
+}
diff --git a/examples/parts/button.c b/examples/parts/button.c
new file mode 100644 (file)
index 0000000..2b89683
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+       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;
+}
+
diff --git a/examples/parts/button.h b/examples/parts/button.h
new file mode 100644 (file)
index 0000000..51cecc8
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+       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__*/
index 90e56463aa981f43e007779b111f4d7eb138fd00..ab80a9049be0407e34b4cd91c700d53063d8061e 100644 (file)
 
 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}
@@ -42,25 +35,17 @@ IPATH       += ../../shared
 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}
@@ -78,6 +63,3 @@ ${target}     :       obj/${target}.o
 clean:
        rm -rf ${target} obj *.a
 
-# include the dependency files generated by gcc, if any
--include ${wildcard obj/*.d}
-
index cc1b396c2754a17306760bfecbe5c19dc6adee33..f9945c2d310d18e941c312ccc2c39c4f5187ce74 100644 (file)
@@ -27,6 +27,7 @@
 #include "avr_uart.h"
 #include "avr_timer8.h"
 #include "avr_spi.h"
+#include "avr_twi.h"
 
 #define _AVR_IO_H_
 #define __ASSEMBLER__
@@ -43,6 +44,7 @@ static struct mcu_t {
        avr_uart_t              uart0,uart1;
        avr_timer8_t    timer0,timer2;
        avr_spi_t               spi;
+       avr_twi_t               twi;
 } mcu = {
        .core = {
                .mmcu = "atmega644",
@@ -220,6 +222,33 @@ static struct mcu_t {
                        .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()
@@ -248,6 +277,7 @@ static void init(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);
 }
 
 static void reset(struct avr_t * avr)
index 7b1f29386b845674753aeb1930c6ca4cc6054914..21ed0fb315f471b00fb940ae089bfe75230b2b0d 100644 (file)
@@ -37,6 +37,7 @@ void mx8_init(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)
index 97eb61e70b8e40c936eb42fd6392d08c65e9ef0e..4ab93a5252940040dcca7fc37cf988974dcaea44 100644 (file)
@@ -29,6 +29,7 @@
 #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);
@@ -43,6 +44,7 @@ struct mcu_t {
        avr_uart_t              uart;
        avr_timer8_t    timer0,timer2;
        avr_spi_t               spi;
+       avr_twi_t               twi;
 };
 
 #ifdef SIM_CORENAME
@@ -196,6 +198,33 @@ struct mcu_t 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 */
 
diff --git a/simavr/sim/avr_twi.c b/simavr/sim/avr_twi.c
new file mode 100644 (file)
index 0000000..3c4d120
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+       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);
+}
+
diff --git a/simavr/sim/avr_twi.h b/simavr/sim/avr_twi.h
new file mode 100644 (file)
index 0000000..31c3ca5
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+       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_ */
diff --git a/simavr/sim/sim_twi.c b/simavr/sim/sim_twi.c
new file mode 100644 (file)
index 0000000..9d6501e
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+       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);
+}
+
diff --git a/simavr/sim/sim_twi.h b/simavr/sim/sim_twi.h
new file mode 100644 (file)
index 0000000..7f383cb
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+       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_ */
index e75a12f17601e53585b58ce4ea82341edaf67ac7..900ad7534c945abe3be56eb73f8271213d0c5070 100644 (file)
 #      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