Cores, decoder, uart, ioports - lots of changes
authorMichel Pollet <buserror@gmail.com>
Mon, 30 Nov 2009 21:36:55 +0000 (21:36 +0000)
committerMichel Pollet <buserror@gmail.com>
Mon, 30 Nov 2009 21:36:55 +0000 (21:36 +0000)
+ Cores now use eeprom declare macro
+ Cores now use the "TXCE" etc bits
+ Uart now raise TXC interupt/flag
+ ioports now use new internal IRQ system
+ New command line options for mcu, freq and trace
+ Decoder updates:
  - Fixed the last known "crash" bug.
  - Added cycles to most multi-cycle opcodes.
  - Added optional stack frame watcher
  - Skip instruction now handle 32 bits skips

Signed-off-by: Michel Pollet <buserror@gmail.com>
15 files changed:
simavr/Makefile
simavr/cores/sim_mega644.c
simavr/cores/sim_megax8.h
simavr/cores/sim_tiny85.c
simavr/sim/avr_eeprom.c
simavr/sim/avr_eeprom.h
simavr/sim/avr_ioport.c
simavr/sim/avr_ioport.h
simavr/sim/avr_uart.c
simavr/sim/avr_uart.h
simavr/sim/sim_core.c
simavr/sim/sim_core.h
simavr/sim/sim_elf.c
simavr/sim/simavr.c
simavr/sim/simavr.h

index b076154..ee25d00 100644 (file)
@@ -45,7 +45,7 @@ all:  obj ${target}
 obj:
        @mkdir -p obj
 
-obj/sim_%.o : cores/sim_%.h cores/sim_core_declare.h sim/*.h
+obj/sim_%.o : cores/sim_%.h ${wildcard cores/*.h} ${wildcard sim/*.h}
 obj/sim_%.o : cores/sim_%.c
        @gcc $(CFLAGS) \
                -I/usr/lib/avr/include/ \
index 813e551..a063ca2 100644 (file)
@@ -49,21 +49,7 @@ static struct mcu_t {
                .init = init,
                .reset = reset,
        },
-       .eeprom = {
-               .size = E2END+1,
-               .r_eearh = EEARH,
-               .r_eearl = EEARL,
-               .r_eedr = EEDR,
-               .r_eecr = EECR,
-               .eepm = { AVR_IO_REGBIT(EECR, EEPM0), AVR_IO_REGBIT(EECR, EEPM1) },
-               .eempe = AVR_IO_REGBIT(EECR, EEMPE),
-               .eepe = AVR_IO_REGBIT(EECR, EEPE),
-               .eere = AVR_IO_REGBIT(EECR, EERE),
-               .ready = {
-                       .enable = AVR_IO_REGBIT(EECR, EERIE),
-                       .vector = EE_READY_vect,
-               },
-       },
+       AVR_EEPROM_DECLARE(EE_READY_vect),
        .porta = {
                .name = 'A', .r_port = PORTA, .r_ddr = DDRA, .r_pin = PINA,
                .pcint = {
@@ -105,7 +91,6 @@ static struct mcu_t {
                .disabled = AVR_IO_REGBIT(PRR,PRUSART0),
                .name = '0',
                .r_udr = UDR0,
-               .udre = AVR_IO_REGBIT(UCSR0A, UDRE0),
 
                .r_ucsra = UCSR0A,
                .r_ucsrb = UCSR0B,
@@ -114,14 +99,17 @@ static struct mcu_t {
                .r_ubrrh = UBRR0H,
                .rxc = {
                        .enable = AVR_IO_REGBIT(UCSR0B, RXCIE0),
+                       .raised = AVR_IO_REGBIT(UCSR0A, RXC0),
                        .vector = USART0_RX_vect,
                },
                .txc = {
                        .enable = AVR_IO_REGBIT(UCSR0B, TXCIE0),
+                       .raised = AVR_IO_REGBIT(UCSR0A, TXC0),
                        .vector = USART0_TX_vect,
                },
                .udrc = {
                        .enable = AVR_IO_REGBIT(UCSR0B, UDRIE0),
+                       .raised = AVR_IO_REGBIT(UCSR0A, UDRE0),
                        .vector = USART0_UDRE_vect,
                },
        },
@@ -129,7 +117,6 @@ static struct mcu_t {
                .disabled = AVR_IO_REGBIT(PRR,PRUSART1),
                .name = '1',
                .r_udr = UDR1,
-               .udre = AVR_IO_REGBIT(UCSR1A, UDRE1),
 
                .r_ucsra = UCSR1A,
                .r_ucsrb = UCSR1B,
@@ -138,14 +125,17 @@ static struct mcu_t {
                .r_ubrrh = UBRR1H,
                .rxc = {
                        .enable = AVR_IO_REGBIT(UCSR1B, RXCIE1),
+                       .raised = AVR_IO_REGBIT(UCSR1A, RXC1),
                        .vector = USART1_RX_vect,
                },
                .txc = {
                        .enable = AVR_IO_REGBIT(UCSR1B, TXCIE1),
+                       .raised = AVR_IO_REGBIT(UCSR1A, TXC1),
                        .vector = USART1_TX_vect,
                },
                .udrc = {
                        .enable = AVR_IO_REGBIT(UCSR1B, UDRIE1),
+                       .raised = AVR_IO_REGBIT(UCSR1A, UDRE1),
                        .vector = USART1_UDRE_vect,
                },
        },
index cbe6de2..682b2c4 100644 (file)
@@ -62,21 +62,7 @@ struct mcu_t SIM_CORENAME = {
                .init = mx8_init,
                .reset = mx8_reset,
        },
-       .eeprom = {
-               .size = E2END+1,
-               .r_eearh = EEARH,
-               .r_eearl = EEARL,
-               .r_eedr = EEDR,
-               .r_eecr = EECR,
-               .eepm = { AVR_IO_REGBIT(EECR, EEPM0), AVR_IO_REGBIT(EECR, EEPM1) },
-               .eempe = AVR_IO_REGBIT(EECR, EEMPE),
-               .eepe = AVR_IO_REGBIT(EECR, EEPE),
-               .eere = AVR_IO_REGBIT(EECR, EERE),
-               .ready = {
-                       .enable = AVR_IO_REGBIT(EECR, EERIE),
-                       .vector = EE_READY_vect,
-               },
-       },
+       AVR_EEPROM_DECLARE(EE_READY_vect),
        .portb = {
                .name = 'B', .r_port = PORTB, .r_ddr = DDRB, .r_pin = PINB,
                .pcint = {
@@ -109,7 +95,6 @@ struct mcu_t SIM_CORENAME = {
                .disabled = AVR_IO_REGBIT(PRR,PRUSART0),
                .name = '0',
                .r_udr = UDR0,
-               .udre = AVR_IO_REGBIT(UCSR0A, UDRE0),
 
                .r_ucsra = UCSR0A,
                .r_ucsrb = UCSR0B,
@@ -118,14 +103,17 @@ struct mcu_t SIM_CORENAME = {
                .r_ubrrh = UBRR0H,
                .rxc = {
                        .enable = AVR_IO_REGBIT(UCSR0B, RXCIE0),
+                       .raised = AVR_IO_REGBIT(UCSR0A, RXC0),
                        .vector = USART_RX_vect,
                },
                .txc = {
                        .enable = AVR_IO_REGBIT(UCSR0B, TXCIE0),
+                       .raised = AVR_IO_REGBIT(UCSR0A, TXC0),
                        .vector = USART_TX_vect,
                },
                .udrc = {
                        .enable = AVR_IO_REGBIT(UCSR0B, UDRIE0),
+                       .raised = AVR_IO_REGBIT(UCSR0A, UDRE0),
                        .vector = USART_UDRE_vect,
                },
        },
index 850005c..e4d7af3 100644 (file)
@@ -47,21 +47,7 @@ static struct mcu_t {
                .init = init,
                .reset = reset,
        },
-       .eeprom = {
-               .size = E2END+1,
-               .r_eearh = EEARH,
-               .r_eearl = EEARL,
-               .r_eedr = EEDR,
-               .r_eecr = EECR,
-               .eepm = { AVR_IO_REGBIT(EECR, EEPM0), AVR_IO_REGBIT(EECR, EEPM1) },
-               .eempe = AVR_IO_REGBIT(EECR, EEMPE),
-               .eepe = AVR_IO_REGBIT(EECR, EEPE),
-               .eere = AVR_IO_REGBIT(EECR, EERE),
-               .ready = {
-                       .enable = AVR_IO_REGBIT(EECR, EERIE),
-                       .vector = EE_RDY_vect,// EE_READY_vect,
-               },
-       },
+       AVR_EEPROM_DECLARE(EE_RDY_vect),
        .portb = {
                .name = 'B',  .r_port = PORTB, .r_ddr = DDRB, .r_pin = PINB,
                .pcint = {
index f7a2d60..4045027 100644 (file)
@@ -57,7 +57,7 @@ static void avr_eeprom_write(struct avr_t * avr, uint8_t addr, uint8_t v, void *
        
        if (eempe && avr_regbit_get(avr, p->eepe)) {    // write operation
                uint16_t addr = avr->data[p->r_eearl] | (avr->data[p->r_eearh] << 8);
-               printf("eeprom write %04x <- %02x\n", addr, avr->data[p->r_eedr]);
+       //      printf("eeprom write %04x <- %02x\n", addr, avr->data[p->r_eedr]);
                p->eeprom[addr] = avr->data[p->r_eedr]; 
                // automaticaly clears that bit (?)
                p->eempe_clear_timer = 0;
@@ -68,7 +68,7 @@ static void avr_eeprom_write(struct avr_t * avr, uint8_t addr, uint8_t v, void *
        if (avr_regbit_get(avr, p->eere)) {     // read operation
                uint16_t addr = avr->data[p->r_eearl] | (avr->data[p->r_eearh] << 8);
                avr->data[p->r_eedr] = p->eeprom[addr];
-               printf("eeprom read %04x : %02x\n", addr, p->eeprom[addr]);
+       //      printf("eeprom read %04x : %02x\n", addr, p->eeprom[addr]);
        }
 
        // autocleared
index 37585bf..c7f1dcd 100644 (file)
@@ -58,4 +58,27 @@ typedef struct avr_eeprom_desc_t {
 #define AVR_IOCTL_EEPROM_GET   AVR_IOCTL_DEF('e','e','g','p')
 #define AVR_IOCTL_EEPROM_SET   AVR_IOCTL_DEF('e','e','s','p')
 
+
+/*
+ * the eeprom block seems to be very similar across AVRs, 
+ * so here is a macro to declare a "typical" one in a core.
+ */
+
+#define AVR_EEPROM_DECLARE(_vector) \
+       .eeprom = {\
+               .size = E2END+1,\
+               .r_eearh = EEARH,\
+               .r_eearl = EEARL,\
+               .r_eedr = EEDR,\
+               .r_eecr = EECR,\
+               .eepm = { AVR_IO_REGBIT(EECR, EEPM0), AVR_IO_REGBIT(EECR, EEPM1) },\
+               .eempe = AVR_IO_REGBIT(EECR, EEMPE),\
+               .eepe = AVR_IO_REGBIT(EECR, EEPE),\
+               .eere = AVR_IO_REGBIT(EECR, EERE),\
+               .ready = {\
+                       .enable = AVR_IO_REGBIT(EECR, EERIE),\
+                       .vector = _vector,\
+               },\
+       }
+
 #endif /* __AVR_EEPROM_H__ */
index 157a624..2bb4483 100644 (file)
@@ -52,51 +52,76 @@ static void avr_ioport_write(struct avr_t * avr, uint8_t addr, uint8_t v, void *
 
                avr_core_watch_write(avr, addr, v);
                if (v != oldv) {
-                       int raise = 1;
                        int mask = v ^ oldv;
-                       if (p->r_pcint)
-                               raise = avr->data[p->r_pcint] & mask;
-                       if (raise)
-                               avr_raise_interupt(avr, &p->pcint);
+
+                       // raise the internal IRQ callbacks
+                       for (int i = 0; i < 8; i++)
+                               if (mask & (1 << i))
+                                       avr_raise_irq(avr, p->irq + i, (v >> i) & 1);
+                       avr_raise_irq(avr, p->irq + IOPORT_IRQ_PIN_ALL, v);
                }
+       }
+}
+
+/*
+ * this is out "main" pin change callback, it can be triggered by either the
+ * AVR code, or any external piece of code that see fit to do it.
+ * Either way, this will raise pin change interupts, if needed
+ */
+void avr_ioport_irq_notify(avr_t * avr, struct avr_irq_t * irq, uint32_t value, void * param)
+{
+       avr_ioport_t * p = (avr_ioport_t *)param;
+       if (p->r_pcint) {
+               int raise = avr->data[p->r_pcint] & (1 << irq->irq);
+               if (raise)
+                       avr_raise_interupt(avr, &p->pcint);
+       }
+       
+}
 
+static int avr_ioport_ioctl(avr_t * avr, avr_io_t * port, uint32_t ctl, void * io_param)
+{
+       avr_ioport_t * p = (avr_ioport_t *)port;
+       int res = -1;
 
-               if (p->name == 'D') {
-                       static int cs = -1;
-                       if ((oldv & 0xf0) != (v & 0xf0)) {
-                               for (int i = 0; i < 4; i++) {
-                                       
-                               }
-                       } 
-                       {
-                       }
-               }
+       switch(ctl) {
+               case AVR_IOCTL_IOPORT_GETIRQ ... AVR_IOCTL_IOPORT_GETIRQ + IOPORT_IRQ_PIN_ALL: {
+                       printf("%s: AVR_IOCTL_IOPORT_GETIRQ  %d\n", __FUNCTION__, 0);
+               }       break;
        }
+       
+       return res;
 }
 
 static void avr_ioport_reset(avr_t * avr, avr_io_t * port)
 {
+       avr_ioport_t * p = (avr_ioport_t *)port;
+       for (int i = 0; i < IOPORT_IRQ_PIN_ALL; i++) 
+               avr_irq_register_notify(avr, p->irq + i, avr_ioport_irq_notify, p);
 }
 
 static avr_io_t        _io = {
        .kind = "io",
        .run = avr_ioport_run,
        .reset = avr_ioport_reset,
+       .ioctl = avr_ioport_ioctl,
 };
 
-void avr_ioport_init(avr_t * avr, avr_ioport_t * port)
+void avr_ioport_init(avr_t * avr, avr_ioport_t * p)
 {
-       port->io = _io;
+       p->io = _io;
        printf("%s PIN%c 0x%02x DDR%c 0x%02x PORT%c 0x%02x\n",
                __FUNCTION__,
-               port->name, port->r_pin,
-               port->name, port->r_ddr,
-               port->name, port->r_port);
+               p->name, p->r_pin,
+               p->name, p->r_ddr,
+               p->name, p->r_port);
 
-       avr_register_io(avr, &port->io);
-       avr_register_vector(avr, &port->pcint);
+       p->irq = avr_alloc_irq(avr, 0, IOPORT_IRQ_PIN_ALL+1);
+       
+       avr_register_io(avr, &p->io);
+       avr_register_vector(avr, &p->pcint);
 
-       avr_register_io_write(avr, port->r_port, avr_ioport_write, port);
-       avr_register_io_read(avr, port->r_pin, avr_ioport_read, port);
+       avr_register_io_write(avr, p->r_port, avr_ioport_write, p);
+       avr_register_io_read(avr, p->r_pin, avr_ioport_read, p);
 }
 
index 9f38995..c2daad5 100644 (file)
 
 #include "simavr.h"
 
+enum {
+       IOPORT_IRQ_PIN0 = 0,
+       IOPORT_IRQ_PIN1,IOPORT_IRQ_PIN2,IOPORT_IRQ_PIN3,IOPORT_IRQ_PIN4,
+       IOPORT_IRQ_PIN5,IOPORT_IRQ_PIN6,IOPORT_IRQ_PIN7,
+       IOPORT_IRQ_PIN_ALL
+};
+
+// add IOPORT_IRQ_PIN* to this to get the real IRQ
+#define AVR_IOCTL_IOPORT_GETIRQ AVR_IOCTL_DEF('i','o','g',0)
+
 typedef struct avr_ioport_t {
        avr_io_t        io;
        char name;
@@ -33,9 +43,11 @@ typedef struct avr_ioport_t {
 
        avr_int_vector_t pcint; // PCINT vector
        uint8_t r_pcint;                // pcint 8 pins mask
-       
+
+       avr_irq_t * irq;
 } avr_ioport_t;
 
 void avr_ioport_init(avr_t * avr, avr_ioport_t * port);
 
+
 #endif /* __AVR_IOPORT_H__ */
index 06aca7a..f016721 100644 (file)
@@ -46,7 +46,10 @@ static void avr_uart_write(struct avr_t * avr, uint8_t addr, uint8_t v, void * p
        if (addr == p->r_udr) {
        //      printf("UDR%c(%02x) = %02x\n", p->name, addr, v);
                avr_core_watch_write(avr, addr, v);
-               avr_regbit_set(avr, p->udre);
+
+               // if the interupts are not used, still raised the UDRE and TXC flaga
+               avr_raise_interupt(avr, &p->udrc);
+               avr_raise_interupt(avr, &p->txc);
 
                static char buf[128];
                static int l = 0;
@@ -57,12 +60,25 @@ static void avr_uart_write(struct avr_t * avr, uint8_t addr, uint8_t v, void * p
                        printf("\e[32m%s\e[0m\n", buf);
                }
        }
+       if (addr == p->r_ucsra) {
+               // get the bits before the write
+               uint8_t udre = avr_regbit_get(avr, p->udrc.raised);
+               uint8_t txc = avr_regbit_get(avr, p->txc.raised);
+               
+               avr_core_watch_write(avr, addr, v);
+
+               // if writing one to a one, clear bit
+               if (udre && avr_regbit_get(avr, p->udrc.raised))
+                       avr_regbit_clear(avr, p->udrc.raised);
+               if (txc && avr_regbit_get(avr, p->txc.raised))
+                       avr_regbit_clear(avr, p->txc.raised);
+       }
 }
 
 void avr_uart_reset(avr_t * avr, struct avr_io_t *io)
 {
        avr_uart_t * p = (avr_uart_t *)io;
-       avr_regbit_set(avr, p->udre);
+       avr_regbit_set(avr, p->udrc.raised);
 }
 
 static avr_io_t        _io = {
@@ -79,6 +95,7 @@ void avr_uart_init(avr_t * avr, avr_uart_t * p)
        printf("%s UART%c UDR=%02x\n", __FUNCTION__, p->name, p->r_udr);
 
        avr_register_io_write(avr, p->r_udr, avr_uart_write, p);
+       avr_register_io_write(avr, p->r_ucsra, avr_uart_write, p);
        avr_register_io_read(avr, p->r_udr, avr_uart_read, p);
 
 }
index 7ac6092..dec4cee 100644 (file)
@@ -38,10 +38,7 @@ typedef struct avr_uart_t {
 
        avr_int_vector_t rxc;
        avr_int_vector_t txc;
-       avr_int_vector_t udrc;
-
-       avr_regbit_t    udre; // AVR_IO_REGBIT(UCSR0A, UDRE0),
-       
+       avr_int_vector_t udrc;  
 } avr_uart_t;
 
 void avr_uart_init(avr_t * avr, avr_uart_t * port);
index 53271e1..0980ab5 100644 (file)
@@ -252,6 +252,19 @@ void avr_dump_state(avr_t * avr)
        avr->old[avr->old_pci].sp = _avr_sp_get(avr);\
        avr->old_pci = (avr->old_pci + 1) & (OLD_PC_SIZE-1);\
 
+#if AVR_STACK_WATCH
+#define STACK_FRAME_PUSH()\
+       avr->stack_frame[avr->stack_frame_index].pc = avr->pc;\
+       avr->stack_frame[avr->stack_frame_index].sp = _avr_sp_get(avr);\
+       avr->stack_frame_index++; 
+#define STACK_FRAME_POP()\
+       if (avr->stack_frame_index > 0) \
+               avr->stack_frame_index--;
+#else
+#define STACK_FRAME_PUSH()
+#define STACK_FRAME_POP()
+#endif
+
 /****************************************************************************\
  *
  * Helper functions for calculating the status register bit values.
@@ -313,6 +326,17 @@ get_compare_overflow (uint8_t res, uint8_t rd, uint8_t rr)
     return (rd & ~rr & ~res) | (~rd & rr & res);
 }
 
+static inline int _avr_is_instruction_32_bits(avr_t * avr, uint32_t pc)
+{
+       uint16_t o = (avr->flash[pc] | (avr->flash[pc+1] << 8)) & 0xfc0f;
+       return  o == 0x9200 || // STS ! Store Direct to Data Space
+                       o == 0x9000 || // LDS Load Direct from Data Space
+                       o == 0x940c || // JMP Long Jump
+                       o == 0x940d || // JMP Long Jump
+                       o == 0x940e ||  // CALL Long Call to sub
+                       o == 0x940f; // CALL Long Call to sub
+}
+
 /*
  * Main opcode decoder
  * 
@@ -323,10 +347,9 @@ get_compare_overflow (uint8_t res, uint8_t rd, uint8_t rr)
  * ones scream to be factored).
  * I assume that the decoder could easily be 2/3 of it's current size.
  * 
- * The core 'almost' work. There is a case where it munches the stack, problem to be
- * debugged.
- * 
- * It lacks a couple of multiply instructions, and the "extended" XMega jumps.
+ * + It lacks the "extended" XMega jumps. 
+ * + It also doesn't check wether the core it's
+ *   emulating is suposed to have the fancy instructions, like multiply and such.
  * 
  * for now all instructions take "one" cycle, the cycle+=<extra> needs to be added.
  */
@@ -408,6 +431,56 @@ uint16_t avr_run_one(avr_t * avr)
                                                                        _avr_set_r(avr, d, avr->data[r]);
                                                                        _avr_set_r(avr, d+1, avr->data[r+1]);
                                                                }       break;
+                                                               case 0x0200: {  // MULS – Multiply Signed 0000 0010 dddd rrrr
+                                                                       int8_t r = opcode & 0xf;
+                                                                       int8_t d = (opcode >> 4) & 0xf;
+                                                                       int16_t res = ((int8_t)avr->data[r]) * ((int8_t)avr->data[d]);
+                                                                       STATE("muls %s[%d], %s[%02x] = %d\n", avr_regname(d), ((int8_t)avr->data[d]), avr_regname(r), ((int8_t)avr->data[r]), res);
+                                                                       _avr_set_r(avr, 0, res);
+                                                                       _avr_set_r(avr, 1, res >> 8);
+                                                                       avr->sreg[S_C] = (res >> 15) & 1;
+                                                                       avr->sreg[S_Z] = res == 0;
+                                                                       SREG();
+                                                               }       break;
+                                                               case 0x0300: {  // multiplications
+                                                                       int8_t r = 16 + (opcode & 0x7);
+                                                                       int8_t d = 16 + ((opcode >> 4) & 0x7);
+                                                                       int16_t res = 0;
+                                                                       uint8_t c = 0;
+                                                                       const char * name = "";
+                                                                       switch (opcode & 0x88) {
+                                                                               case 0x00:      // MULSU – Multiply Signed Unsigned 0000 0011 0ddd 0rrr
+                                                                                       res = ((uint8_t)avr->data[r]) * ((int8_t)avr->data[d]);
+                                                                                       c = (res >> 15) & 1;
+                                                                                       name = "mulsu";
+                                                                                       break;
+                                                                               case 0x08:      // FMUL Fractional Multiply Unsigned 0000 0011 0ddd 1rrr
+                                                                                       res = ((uint8_t)avr->data[r]) * ((uint8_t)avr->data[d]);
+                                                                                       c = (res >> 15) & 1;
+                                                                                       res <<= 1;
+                                                                                       name = "fmul";
+                                                                                       break;
+                                                                               case 0x80:      // FMULS – Multiply Signed  0000 0011 1ddd 0rrr
+                                                                                       res = ((int8_t)avr->data[r]) * ((int8_t)avr->data[d]);
+                                                                                       c = (res >> 15) & 1;
+                                                                                       res <<= 1;
+                                                                                       name = "fmuls";
+                                                                                       break;
+                                                                               case 0x88:      // FMULSU – Multiply Signed Unsigned 0000 0011 1ddd 0rrr
+                                                                                       res = ((uint8_t)avr->data[r]) * ((int8_t)avr->data[d]);
+                                                                                       c = (res >> 15) & 1;
+                                                                                       res <<= 1;
+                                                                                       name = "fmulsu";
+                                                                                       break;
+                                                                       }
+                                                                       cycle++;
+                                                                       STATE("%s %s[%d], %s[%02x] = %d\n", name, avr_regname(d), ((int8_t)avr->data[d]), avr_regname(r), ((int8_t)avr->data[r]), res);
+                                                                       _avr_set_r(avr, 0, res);
+                                                                       _avr_set_r(avr, 1, res >> 8);
+                                                                       avr->sreg[S_C] = c;
+                                                                       avr->sreg[S_Z] = res == 0;
+                                                                       SREG();
+                                                               }       break;
                                                                default: _avr_invalid_opcode(avr);
                                                        }
                                        }
@@ -434,8 +507,13 @@ uint16_t avr_run_one(avr_t * avr)
                                        get_r_d_10(opcode);
                                        uint16_t res = vd == vr;
                                        STATE("cpse %s[%02x], %s[%02x]\t; Will%s skip\n", avr_regname(d), avr->data[d], avr_regname(r), avr->data[r], res ? "":"not ");
-                                       if (res)
-                                               new_pc += 2;
+                                       if (res) {
+                                               if (_avr_is_instruction_32_bits(avr, new_pc)) {
+                                                       new_pc += 4; cycle += 2;
+                                               } else {
+                                                       new_pc += 2; cycle++;
+                                               }
+                                       }
                                }       break;
                                case 0x1400: {  // CP Compare 0000 10 rd dddd rrrr
                                        get_r_d_10(opcode);
@@ -466,21 +544,7 @@ uint16_t avr_run_one(avr_t * avr)
                                        avr->sreg[S_S] = avr->sreg[S_N] ^ avr->sreg[S_V];
                                        SREG();
                                }       break;
-                               default:
-                                       switch (opcode & 0xff00) {
-                                               case 0x0200: {  // MULS – Multiply Signed 0000 0010 dddd rrrr
-                                                       int8_t r = opcode & 0xf;
-                                                       int8_t d = (opcode >> 4) & 0xf;
-                                                       int16_t res = ((int8_t)avr->data[r]) * ((int8_t)avr->data[d]);
-                                                       STATE("muls %s[%d], %s[%02x] = %d\n", avr_regname(d), ((int8_t)avr->data[d]), avr_regname(r), ((int8_t)avr->data[r]), res);
-                                                       _avr_set_r(avr, 0, res);
-                                                       _avr_set_r(avr, 1, res >> 8);
-                                                       avr->sreg[S_C] = (res >> 15) & 1;
-                                                       avr->sreg[S_Z] = res == 0;
-                                                       SREG();
-                                               }       break;
-                                               default: _avr_invalid_opcode(avr);
-                                       }
+                               default: _avr_invalid_opcode(avr);
                        }
                }       break;
 
@@ -609,7 +673,7 @@ uint16_t avr_run_one(avr_t * avr)
                                case 0x8000: {  // LD (LDD) – Load Indirect using Z 10q0 qq0r rrrr 0qqq
                                        uint16_t v = avr->data[R_ZL] | (avr->data[R_ZH] << 8);
                                        uint8_t r = (opcode >> 4) & 0x1f;
-                                       uint8_t q = ((opcode & 0x2000) >> 7) | ((opcode & 0x0c00) >> 7) | (opcode & 0x7);
+                                       uint8_t q = ((opcode & 0x2000) >> 8) | ((opcode & 0x0c00) >> 7) | (opcode & 0x7);
 
                                        if (opcode & 0x0200) {
                                                STATE("st (Z+%d[%04x]), %s[%02x]\n", q, v+q, avr_regname(r), avr->data[r]);
@@ -618,12 +682,13 @@ uint16_t avr_run_one(avr_t * avr)
                                                STATE("ld %s, (Z+%d[%04x])=[%02x]\n", avr_regname(r), q, v+q, avr->data[v+q]);
                                                _avr_set_r(avr, r, _avr_get_ram(avr, v+q));
                                        }
+                                       cycle += 2;
                                }       break;
                                case 0xa008:
                                case 0x8008: {  // LD (LDD) – Load Indirect using Y 10q0 qq0r rrrr 1qqq
                                        uint16_t v = avr->data[R_YL] | (avr->data[R_YH] << 8);
                                        uint8_t r = (opcode >> 4) & 0x1f;
-                                       uint8_t q = ((opcode & 0x2000) >> 7) | ((opcode & 0x0c00) >> 7) | (opcode & 0x7);
+                                       uint8_t q = ((opcode & 0x2000) >> 8) | ((opcode & 0x0c00) >> 7) | (opcode & 0x7);
 
                                        if (opcode & 0x0200) {
                                                STATE("st (Y+%d[%04x]), %s[%02x]\n", q, v+q, avr_regname(r), avr->data[r]);
@@ -632,6 +697,7 @@ uint16_t avr_run_one(avr_t * avr)
                                                STATE("ld %s, (Y+%d[%04x])=[%02x]\n", avr_regname(r), q, v+q, avr->data[v+q]);
                                                _avr_set_r(avr, r, _avr_get_ram(avr, v+q));
                                        }
+                                       cycle += 2;
                                }       break;
                                default: _avr_invalid_opcode(avr);
                        }
@@ -659,23 +725,27 @@ uint16_t avr_run_one(avr_t * avr)
                                        uint16_t z = avr->data[R_ZL] | (avr->data[R_ZH] << 8);
                                        STATE("ijmp Z[%04x]\n", z << 1);
                                        new_pc = z << 1;
+                                       cycle++;
                                        TRACE_JUMP();
                                }       break;
                                case 0x9509: { // ICALL Indirect Call to Subroutine
                                        uint16_t z = avr->data[R_ZL] | (avr->data[R_ZH] << 8);
                                        STATE("icall Z[%04x]\n", z << 1);
-
                                        _avr_push16(avr, new_pc >> 1);
                                        new_pc = z << 1;
+                                       cycle += 2;
                                        TRACE_JUMP();
+                                       STACK_FRAME_PUSH();
                                }       break;
                                case 0x9518:    // RETI
                                case 0x9508: {  // RET
                                        new_pc = _avr_pop16(avr) << 1;
                                        if (opcode & 0x10)      // reti
                                                avr->sreg[S_I] = 1;
+                                       cycle += 3;
                                        STATE("ret%s\n", opcode & 0x10 ? "i" : "");
                                        TRACE_JUMP();
+                                       STACK_FRAME_POP();
                                }       break;
                                case 0x95c8: {  // LPM Load Program Memory R0 <- (Z)
                                        uint16_t z = avr->data[R_ZL] | (avr->data[R_ZH] << 8);
@@ -700,6 +770,14 @@ uint16_t avr_run_one(avr_t * avr)
                                }       break;
                                default:  {
                                        switch (opcode & 0xfe0f) {
+                                               case 0x9000: {  // LDS Load Direct from Data Space, 32 bits
+                                                       uint8_t r = (opcode >> 4) & 0x1f;
+                                                       uint16_t x = (avr->flash[new_pc+1] << 8) | avr->flash[new_pc];
+                                                       new_pc += 2;
+                                                       STATE("lds %s[%02x], 0x%04x\n", avr_regname(r), avr->data[r], x);
+                                                       _avr_set_r(avr, r, _avr_get_ram(avr, x));
+                                                       cycle++;
+                                               }       break;
                                                case 0x9005:
                                                case 0x9004: {  // LPM Load Program Memory 1001 000d dddd 01oo
                                                        uint16_t z = avr->data[R_ZL] | (avr->data[R_ZH] << 8);
@@ -712,6 +790,7 @@ uint16_t avr_run_one(avr_t * avr)
                                                                _avr_set_r(avr, R_ZH, z >> 8);
                                                                _avr_set_r(avr, R_ZL, z);
                                                        }
+                                                       cycle += 2;
                                                }       break;
                                                case 0x900c:
                                                case 0x900d:
@@ -734,7 +813,7 @@ uint16_t avr_run_one(avr_t * avr)
                                                        uint8_t r = (opcode >> 4) & 0x1f;
                                                        uint16_t x = (avr->data[R_XH] << 8) | avr->data[R_XL];
                                                        STATE("st %sX[%04x]%s, %s[%02x] \n", op == 2 ? "--" : "", x, op == 1 ? "++" : "", avr_regname(r), avr->data[r]);
-
+                                                       cycle++;
                                                        if (op == 2) x--;
                                                        _avr_set_ram(avr, x, avr->data[r]);
                                                        if (op == 1) x++;
@@ -747,7 +826,7 @@ uint16_t avr_run_one(avr_t * avr)
                                                        uint8_t r = (opcode >> 4) & 0x1f;
                                                        uint16_t y = (avr->data[R_YH] << 8) | avr->data[R_YL];
                                                        STATE("ld %s, %sY[%04x]%s\n", avr_regname(r), op == 2 ? "--" : "", y, op == 1 ? "++" : "");
-
+                                                       cycle++;
                                                        if (op == 2) y--;
                                                        _avr_set_r(avr, r, _avr_get_ram(avr, y));
                                                        if (op == 1) y++;
@@ -760,7 +839,7 @@ uint16_t avr_run_one(avr_t * avr)
                                                        uint8_t r = (opcode >> 4) & 0x1f;
                                                        uint16_t y = (avr->data[R_YH] << 8) | avr->data[R_YL];
                                                        STATE("st %sY[%04x]%s, %s[%02x] \n", op == 2 ? "--" : "", y, op == 1 ? "++" : "", avr_regname(r), avr->data[r]);
-
+                                                       cycle++;
                                                        if (op == 2) y--;
                                                        _avr_set_ram(avr, y, avr->data[r]);
                                                        if (op == 1) y++;
@@ -780,7 +859,6 @@ uint16_t avr_run_one(avr_t * avr)
                                                        uint8_t r = (opcode >> 4) & 0x1f;
                                                        uint16_t z = (avr->data[R_ZH] << 8) | avr->data[R_ZL];
                                                        STATE("ld %s, %sZ[%04x]%s\n", avr_regname(r), op == 2 ? "--" : "", z, op == 1 ? "++" : "");
-
                                                        if (op == 2) z--;
                                                        _avr_set_r(avr, r, _avr_get_ram(avr, z));
                                                        if (op == 1) z++;
@@ -793,7 +871,6 @@ uint16_t avr_run_one(avr_t * avr)
                                                        uint8_t r = (opcode >> 4) & 0x1f;
                                                        uint16_t z = (avr->data[R_ZH] << 8) | avr->data[R_ZL];
                                                        STATE("st %sZ[%04x]%s, %s[%02x] \n", op == 2 ? "--" : "", z, op == 1 ? "++" : "", avr_regname(r), avr->data[r]);
-
                                                        if (op == 2) z--;
                                                        _avr_set_ram(avr, z, avr->data[r]);
                                                        if (op == 1) z++;
@@ -805,19 +882,14 @@ uint16_t avr_run_one(avr_t * avr)
                                                        _avr_set_r(avr, r, _avr_pop8(avr));
                                                        uint16_t sp = _avr_sp_get(avr);
                                                        STATE("pop %s (@%04x)[%02x]\n", avr_regname(r), sp, avr->data[sp]);
+                                                       cycle++;
                                                }       break;
                                                case 0x920f: {  // PUSH 1001 001d dddd 1111
                                                        uint8_t r = (opcode >> 4) & 0x1f;
                                                        _avr_push8(avr, avr->data[r]);
                                                        uint16_t sp = _avr_sp_get(avr);
                                                        STATE("push %s[%02x] (@%04x)\n", avr_regname(r), avr->data[r], sp);
-                                               }       break;
-                                               case 0x9000: {  // LDS Load Direct from Data Space, 32 bits
-                                                       uint8_t r = (opcode >> 4) & 0x1f;
-                                                       uint16_t x = (avr->flash[new_pc+1] << 8) | avr->flash[new_pc];
-                                                       new_pc += 2;
-                                                       STATE("lds %s[%02x], 0x%04x\n", avr_regname(r), avr->data[r], x);
-                                                       _avr_set_r(avr, r, _avr_get_ram(avr, x));
+                                                       cycle++;
                                                }       break;
                                                case 0x9400: {  // COM – One’s Complement
                                                        uint8_t r = (opcode >> 4) & 0x1f;
@@ -917,9 +989,9 @@ uint16_t avr_run_one(avr_t * avr)
                                                        uint32_t a = ((opcode & 0x01f0) >> 3) | (opcode & 1);
                                                        uint16_t x = (avr->flash[new_pc+1] << 8) | avr->flash[new_pc];
                                                        a = (a << 16) | x;
-                                               //      printf("jmp %06x\n", a << 1);
                                                        STATE("jmp 0x%06x\n", a);
                                                        new_pc = a << 1;
+                                                       cycle += 2;
                                                        TRACE_JUMP();
                                                }       break;
                                                case 0x940e:
@@ -927,12 +999,13 @@ uint16_t avr_run_one(avr_t * avr)
                                                        uint32_t a = ((opcode & 0x01f0) >> 3) | (opcode & 1);
                                                        uint16_t x = (avr->flash[new_pc+1] << 8) | avr->flash[new_pc];
                                                        a = (a << 16) | x;
-                                               //      printf("call %06x\n", a << 1);
                                                        STATE("call 0x%06x\n", a);
                                                        new_pc += 2;
                                                        _avr_push16(avr, new_pc >> 1);
                                                        new_pc = a << 1;
+                                                       cycle += 3;     // 4 cycles
                                                        TRACE_JUMP();
+                                                       STACK_FRAME_PUSH();
                                                }       break;
 
                                                default: {
@@ -977,14 +1050,20 @@ uint16_t avr_run_one(avr_t * avr)
                                                                        uint8_t res = _avr_get_ram(avr, io) & ~(1 << b);
                                                                        STATE("cbi %s[%04x], 0x%02x = %02x\n", avr_regname(io), avr->data[io], 1<<b, res);
                                                                        _avr_set_ram(avr, io, res);
+                                                                       cycle++;
                                                                }       break;
                                                                case 0x9900: {  // SBIC - Skip if Bit in I/O Register is Cleared 1001 0111 AAAA Abbb
                                                                        uint8_t io = ((opcode >> 3) & 0x1f) + 32;
                                                                        uint8_t b = opcode & 0x7;
                                                                        uint8_t res = _avr_get_ram(avr, io) & (1 << b);
                                                                        STATE("sbic %s[%04x], 0x%02x\t; Will%s branch\n", avr_regname(io), avr->data[io], 1<<b, !res?"":"not ");
-                                                                       if (!res)
-                                                                               new_pc += 2;
+                                                                       if (!res) {
+                                                                               if (_avr_is_instruction_32_bits(avr, new_pc)) {
+                                                                                       new_pc += 4; cycle += 2;
+                                                                               } else {
+                                                                                       new_pc += 2; cycle++;
+                                                                               }
+                                                                       }
                                                                }       break;
                                                                case 0x9a00: {  // SBI - Set Bit in I/O Register 1001 1000 AAAA Abbb
                                                                        uint8_t io = ((opcode >> 3) & 0x1f) + 32;
@@ -992,14 +1071,20 @@ uint16_t avr_run_one(avr_t * avr)
                                                                        uint8_t res = _avr_get_ram(avr, io) | (1 << b);
                                                                        STATE("sbi %s[%04x], 0x%02x = %02x\n", avr_regname(io), avr->data[io], 1<<b, res);
                                                                        _avr_set_ram(avr, io, res);
+                                                                       cycle++;
                                                                }       break;
                                                                case 0x9b00: {  // SBIS - Skip if Bit in I/O Register is Cleared 1001 0111 AAAA Abbb
                                                                        uint8_t io = (opcode >> 3) & 0x1f;
                                                                        uint8_t b = opcode & 0x7;
                                                                        uint8_t res = _avr_get_ram(avr, io + 32) & (1 << b);
                                                                        STATE("sbis %s[%04x], 0x%02x\t; Will%s branch\n", avr_regname(io), avr->data[io], 1<<b, res?"":"not ");
-                                                                       if (res)
-                                                                               new_pc += 2;
+                                                                       if (res) {
+                                                                               if (_avr_is_instruction_32_bits(avr, new_pc)) {
+                                                                                       new_pc += 4; cycle += 2;
+                                                                               } else {
+                                                                                       new_pc += 2; cycle++;
+                                                                               }
+                                                                       }
                                                                }       break;
                                                                default:
                                                                        switch (opcode & 0xfc00) {
@@ -1048,6 +1133,7 @@ uint16_t avr_run_one(avr_t * avr)
                        short o = ((short)(opcode << 4)) >> 4;
                        STATE("rjmp .%d [%04x]\n", o, new_pc + (o << 1));
                        new_pc = new_pc + (o << 1);
+                       cycle++;
                        TRACE_JUMP();
                }       break;
 
@@ -1057,7 +1143,12 @@ uint16_t avr_run_one(avr_t * avr)
                        STATE("rcall .%d [%04x]\n", o, new_pc + (o << 1));
                        _avr_push16(avr, new_pc >> 1);
                        new_pc = new_pc + (o << 1);
-                       TRACE_JUMP();
+                       cycle += 2;
+                       // 'rcall .1' is used as a cheap "push 16 bits of room on the stack"
+                       if (o != 0) {
+                               TRACE_JUMP();
+                               STACK_FRAME_PUSH();
+                       }
                }       break;
 
                case 0xe000: {  // LDI Rd, K 1110 KKKK RRRR KKKK -- aka SER (LDI r, 0xff)
@@ -1086,8 +1177,10 @@ uint16_t avr_run_one(avr_t * avr)
                                        } else {
                                                STATE("%s%c .%d [%04x]\t; Will%s branch\n", set ? "brbs" : "brbc", _sreg_bit_name[s], o, new_pc + (o << 1), branch ? "":" not");
                                        }
-                                       if (branch)
+                                       if (branch) {
+                                               cycle++;
                                                new_pc = new_pc + (o << 1);
+                                       }
                                }       break;
                                case 0xf800:
                                case 0xf900: {  // BLD – Bit Store from T into a Bit in Register 1111 100r rrrr 0bbb
index 0fc5dd5..743979b 100644 (file)
@@ -55,15 +55,27 @@ void avr_dump_state(avr_t * avr);
                }
 
 
+#if AVR_STACK_WATCH
+#define DUMP_STACK() \
+               for (int i = avr->stack_frame_index; i; i--) {\
+                       int pci = i-1;\
+                       printf("\e[31m*** %04x: %-25s sp %04x\e[0m\n",\
+                                       avr->stack_frame[pci].pc, avr->codeline[avr->stack_frame[pci].pc>>1]->symbol, avr->stack_frame[pci].sp);\
+               }
+#else
+#define DUMP_STACK()
+#endif
+
 #define CRASH()  {\
                DUMP_REG();\
-               printf("*** CYCLE %lld\n", avr->cycle);\
+               printf("*** CYCLE %lld PC %04x\n", avr->cycle, avr->pc);\
                for (int i = OLD_PC_SIZE-1; i > 0; i--) {\
                        int pci = (avr->old_pci + i) & 0xf;\
                        printf("\e[31m*** %04x: %-25s RESET -%d; sp %04x\e[0m\n",\
                                        avr->old[pci].pc, avr->codeline[avr->old[pci].pc>>1]->symbol, OLD_PC_SIZE-i, avr->old[pci].sp);\
                }\
                printf("Stack Ptr %04x/%04x = %d \n", _avr_sp_get(avr), avr->ramend, avr->ramend - _avr_sp_get(avr));\
+               DUMP_STACK();\
                exit(1);\
        }
 
index 29552a9..32b2334 100644 (file)
@@ -88,9 +88,8 @@ int elf_read_firmware(const char * file, elf_firmware_t * firmware)
                        firmware->bsssize = s->d_size;
                } else if (!strcmp(name, ".mmcu")) {
                        Elf_Data *s = elf_getdata(scn, NULL);
-                       long f_cpu = s ? *((long*)s->d_buf) : 0;
                        firmware->mmcu = *((avr_mcu_t*)s->d_buf);
-                       printf("%s: setting speed to %ld\n", __FUNCTION__, f_cpu);
+               //      printf("%s: setting speed to %ld\n", __FUNCTION__, f_cpu);
                //      avr->frequency = f_cpu;
                }
 #if ELF_SYMBOLS
index 39481dc..5181f27 100644 (file)
@@ -26,6 +26,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>
+#include <getopt.h>
 #include "simavr.h"
 #include "sim_elf.h"
 
@@ -61,11 +62,12 @@ int avr_init(avr_t * avr)
        avr->data = malloc(avr->ramend + 1);
        memset(avr->data, 0, avr->ramend + 1);
 
-       avr->state = cpu_Running;
+       // cpu is in limbo before init is finished.
+       avr->state = cpu_Limbo;
        avr->frequency = 1000000;       // can be overriden via avr_mcu_section
-       
        if (avr->init)
                avr->init(avr);
+       avr->state = cpu_Running;
        avr_reset(avr); 
        return 0;
 }
@@ -135,27 +137,32 @@ int avr_is_interupt_pending(avr_t * avr, avr_int_vector_t * vector)
        return avr->pending[vector->vector >> 5] & (1 << (vector->vector & 0x1f));
 }
 
-void avr_raise_interupt(avr_t * avr, avr_int_vector_t * vector)
+int avr_raise_interupt(avr_t * avr, avr_int_vector_t * vector)
 {
-       if (!vector->vector)
-               return;
+       if (!vector || !vector->vector)
+               return 0;
 //     printf("%s raising %d\n", __FUNCTION__, vector->vector);
+       // always mark the 'raised' flag to one, even if the interuot is disabled
+       // this allow "pooling" for the "raised" flag, like for non-interupt
+       // driven UART and so so. These flags are often "write one to clear"
+       if (vector->raised.reg)
+               avr_regbit_set(avr, vector->raised);
        if (vector->enable.reg) {
                if (!avr_regbit_get(avr, vector->enable))
-                       return;
+                       return 0;
        }
        if (!avr_is_interupt_pending(avr, vector)) {
                if (!avr->pending_wait)
                        avr->pending_wait = 2;          // latency on interupts ??
                avr->pending[vector->vector >> 5] |= (1 << (vector->vector & 0x1f));
 
-               if (vector->raised.reg)
-                       avr_regbit_set(avr, vector->raised);
                if (avr->state != cpu_Running) {
                //      printf("Waking CPU due to interrupt\n");
                        avr->state = cpu_Running;       // in case we were sleeping
                }
        }
+       // return 'raised' even if it was already pending
+       return 1;
 }
 
 static void avr_clear_interupt(avr_t * avr, int v)
@@ -169,6 +176,69 @@ static void avr_clear_interupt(avr_t * avr, int v)
                avr_regbit_clear(avr, vector->raised);
 }
 
+void avr_init_irq(avr_t * avr, avr_irq_t * irq, uint32_t base, uint32_t count)
+{
+       memset(irq, 0, sizeof(avr_irq_t) * count);
+
+       for (int i = 0; i < count; i++)
+               irq[i].irq = base + i;
+}
+
+avr_irq_t * avr_alloc_irq(avr_t * avr, uint32_t base, uint32_t count)
+{
+       avr_irq_t * irq = (avr_irq_t*)malloc(sizeof(avr_irq_t) * count);
+       avr_init_irq(avr, irq, base, count);
+       return irq;
+}
+
+void avr_irq_register_notify(avr_t * avr, avr_irq_t * irq, avr_irq_notify_t notify, void * param)
+{
+       if (!irq || !notify)
+               return;
+       
+       avr_irq_hook_t *hook = irq->hook;
+       while (hook) {
+               if (hook->notify == notify && hook->param == param)
+                       return; // already there
+               hook = hook->next;
+       }
+       hook = malloc(sizeof(avr_irq_hook_t));
+       memset(hook, 0, sizeof(avr_irq_hook_t));
+       hook->next = irq->hook;
+       hook->notify = notify;
+       hook->param = param;
+       irq->hook = hook;
+}
+
+void avr_raise_irq(avr_t * avr, avr_irq_t * irq, uint32_t value)
+{
+       if (!irq || irq->value == value)
+               return ;
+       avr_irq_hook_t *hook = irq->hook;
+       while (hook) {
+               if (hook->notify) {
+                       if (hook->busy == 0) {
+                               hook->busy++;
+                               hook->notify(avr, irq, value, hook->param);
+                               hook->busy--;
+                       }
+               }
+               hook = hook->next;
+       }
+       irq->value = value;
+}
+
+static void _avr_irq_connect(avr_t * avr, avr_irq_t * irq, uint32_t value, void * param)
+{
+       avr_irq_t * dst = (avr_irq_t*)param;
+       avr_raise_irq(avr, dst, value != 0);
+}
+
+void avr_connect_irq(avr_t * avr, avr_irq_t * src, avr_irq_t * dst)
+{
+       avr_irq_register_notify(avr, src, _avr_irq_connect, dst);
+}
+
 void avr_loadcode(avr_t * avr, uint8_t * code, uint32_t size, uint32_t address)
 {
        memcpy(avr->flash + address, code, size);
@@ -186,15 +256,14 @@ void avr_core_watch_write(avr_t *avr, uint16_t addr, uint8_t v)
                                avr->pc, _avr_sp_get(avr), avr->flash[avr->pc] | (avr->flash[avr->pc]<<8), addr, v);
                CRASH();
        }
-#if 0
+#if AVR_STACK_WATCH
        /*
-        * this only happend when the compiler is doctoring the stack before calls. Or
-        * if there is an invalid pointer somewhere...
+        * this checks that the current "function" is not doctoring the stack frame that is located
+        * higher on the stack than it should be. It's a sign of code that has overrun it's stack
+        * frame and is munching on it's own return address.
         */
-       if (addr > _avr_sp_get(avr)) {
-               avr->trace++;
-               STATE("\e[31mmunching stack SP %04x, A=%04x <= %02x\e[0m\n", _avr_sp_get(avr), addr, v);
-               avr->trace--;
+       if (avr->stack_frame_index > 1 && addr > avr->stack_frame[avr->stack_frame_index-2].sp) {
+               printf("\e[31m%04x : munching stack SP %04x, A=%04x <= %02x\e[0m\n", avr->pc, _avr_sp_get(avr), addr, v);
        }
 #endif
        avr->data[addr] = v;
@@ -315,13 +384,58 @@ avr_kind_t * avr_kind[] = {
        NULL
 };
 
-int main(int argc, const char **argv)
+void display_usage()
+{
+       printf("usage: simavr [-t] [-m <device>] [-f <frequency>] firmware\n");
+       printf("       -t: run full scale decoder trace\n");
+       exit(1);
+}
+
+int main(int argc, char *argv[])
 {
        elf_firmware_t f;
+       long f_cpu = 0;
+       int trace = 0;
+       char name[16] = "";
+       int option_count;
+       int option_index = 0;
+
+       struct option long_options[] = {
+               {"help", no_argument, 0, 'h'},
+               {"mcu", required_argument, 0, 'm'},
+               {"freq", required_argument, 0, 'f'},
+               {"trace", no_argument, 0, 't'},
+               {0, 0, 0, 0}
+       };
+
+       if (argc == 1)
+               display_usage();
+
+       while ((option_count = getopt_long(argc, argv, "thm:f:", long_options, &option_index)) != -1) {
+               switch (option_count) {
+                       case 'h':
+                               display_usage();
+                               break;
+                       case 'm':
+                               strcpy(name, optarg);
+                               break;
+                       case 'f':
+                               f_cpu = atoi(optarg);
+                               break;
+                       case 't':
+                               trace++;
+                               break;
+               }
+       }
+
+       elf_read_firmware(argv[argc-1], &f);
 
-       elf_read_firmware(argv[1], &f);
+       if (strlen(name))
+               strcpy(f.mmcu.name, name);
+       if (f_cpu)
+               f.mmcu.f_cpu = f_cpu;
 
-       printf("firmware %s f=%ld mmcu=%s\n", argv[1], f.mmcu.f_cpu, f.mmcu.name);
+       printf("firmware %s f=%ld mmcu=%s\n", argv[argc-1], f.mmcu.f_cpu, f.mmcu.name);
 
        avr_kind_t * maker = NULL;
        for (int i = 0; avr_kind[i] && !maker; i++) {
@@ -347,7 +461,7 @@ int main(int argc, const char **argv)
                avr_eeprom_desc_t d = { .ee = f.eeprom, .offset = 0, .size = f.eesize };
                avr_ioctl(avr, AVR_IOCTL_EEPROM_SET, &d);
        }
-//     avr->trace = 1;
+       avr->trace = trace;
 
        for (long long i = 0; i < 8000000*10; i++)
 //     for (long long i = 0; i < 80000; i++)
index bc1fd3f..af67f78 100644 (file)
@@ -50,6 +50,7 @@ enum {
  * Core states. This will need populating with debug states for gdb
  */
 enum {
+       cpu_Limbo = 0,  // before initialization is finished
        cpu_Stopped,
        cpu_Running,
        cpu_Sleeping,
@@ -135,6 +136,17 @@ typedef struct avr_t {
        } old[OLD_PC_SIZE]; // catches reset..
        int                     old_pci;
 
+#if AVR_STACK_WATCH
+       #define STACK_FRAME_SIZE        32
+       // this records the call/ret pairs, to try to catch
+       // code that munches the stack -under- their own frame
+       struct {
+               uint32_t        pc;
+               uint16_t        sp;             
+       } stack_frame[STACK_FRAME_SIZE];
+       int                     stack_frame_index;
+#endif
+
        // DEBUG ONLY
        // keeps track of wich registers gets touched by instructions
        // reset before each new instructions. Allows meaningful traces
@@ -226,7 +238,8 @@ int avr_ioctl(avr_t *avr, uint32_t ctl, void * io_param);
 // register an interupt vector. It's only needed if you want to use the "r_raised" flags
 void avr_register_vector(avr_t *avr, avr_int_vector_t * vector);
 // raise an interupt (if enabled). The interupt is latched and will be called later
-void avr_raise_interupt(avr_t * avr, avr_int_vector_t * vector);
+// return non-zero if the interupt was raised and is now pending
+int avr_raise_interupt(avr_t * avr, avr_int_vector_t * vector);
 // return non-zero if the AVR core has any pending interupts
 int avr_has_pending_interupts(avr_t * avr);
 // return nonzero if a soecific interupt vector is pending
@@ -308,6 +321,45 @@ static inline uint8_t avr_regbit_get_array(avr_t * avr, avr_regbit_t *rb, int co
 #define AVR_IO_REGBIT(_io, _bit) { . reg = (_io), .bit = (_bit), .mask = 1 }
 #define AVR_IO_REGBITS(_io, _bit, _mask) { . reg = (_io), .bit = (_bit), .mask = (_mask) }
 
+/*
+ * Internal IRQ system
+ * 
+ * This subsystem allow any piece of code to "register" a hook to be called when an IRQ is
+ * raised. The IRQ definition is up to the module defining it, for example a IOPORT pin change
+ * might be an IRQ in wich case any oiece of code can be notified when a pin has changed state
+ * 
+ * The notify hooks are chained, and duplicates are filtered out so you can't register a
+ * notify hook twice on one particylar IRQ
+ * 
+ * IRQ calling order is not defined, so don't rely on it.
+ * 
+ * IRQ hook needs to be registered in reset() handlers, ie after all modules init() bits
+ * have been called, to prevent race condition of the initialization order.
+ */
+// internal structure for a hook, never seen by the notify procs
+struct avr_irq_t;
+
+typedef void (*avr_irq_notify_t)(avr_t * avr, struct avr_irq_t * irq, uint32_t value, void * param);
+
+typedef struct avr_irq_hook_t {
+       struct avr_irq_hook_t * next;
+       void * param;
+       int busy;       // prevent reentrance of callbacks
+       avr_irq_notify_t notify;
+} avr_irq_hook_t;
+
+typedef struct avr_irq_t {
+       uint32_t                        irq;
+       uint32_t                        value;
+       avr_irq_hook_t *        hook;
+} avr_irq_t;
+
+avr_irq_t * avr_alloc_irq(avr_t * avr, uint32_t base, uint32_t count);
+void avr_init_irq(avr_t * avr, avr_irq_t * irq, uint32_t base, uint32_t count);
+void avr_raise_irq(avr_t * avr, avr_irq_t * irq, uint32_t value);
+// this connects a "source" IRQ to a "destination" IRQ
+void avr_connect_irq(avr_t * avr, avr_irq_t * src, avr_irq_t * dst);
+void avr_irq_register_notify(avr_t * avr, avr_irq_t * irq, avr_irq_notify_t notify, void * param);
 
 #endif /*__SIMAVR_H__*/