core: Simplify changes to SREG
authorMichel Pollet <buserror@gmail.com>
Wed, 6 Jan 2010 22:45:30 +0000 (22:45 +0000)
committerMichel Pollet <buserror@gmail.com>
Wed, 6 Jan 2010 22:47:36 +0000 (22:47 +0000)
SREG is no longer re-synthetized at every instruction,
but only when the firmware reads the register.

Signed-off-by: Michel Pollet <buserror@gmail.com>
simavr/sim/sim_avr.c
simavr/sim/sim_avr.h
simavr/sim/sim_core.c

index 0512c2a..e163f36 100644 (file)
@@ -131,9 +131,8 @@ int avr_run(avr_t * avr)
 
        // if we are stepping one instruction, we "run" for one..
        int step = avr->state == cpu_Step;
-       if (step) {
+       if (step)
                avr->state = cpu_Running;
-       }
        
        uint16_t new_pc = avr->pc;
 
@@ -145,16 +144,21 @@ int avr_run(avr_t * avr)
        }
 
        // if we just re-enabled the interrupts...
-       if (avr->sreg[S_I] && !(avr->data[R_SREG] & (1 << S_I))) {
-       //      printf("*** %s: Renabling interrupts\n", __FUNCTION__);
+       // double buffer the I flag, to detect that edge
+       if (avr->sreg[S_I] && !avr->i_shadow)
                avr->pending_wait++;
-       }
+       avr->i_shadow = avr->sreg[S_I];
+       
+       // run IO modules that wants it
        avr_io_t * port = avr->io_port;
        while (port) {
                if (port->run)
                        port->run(port);
                port = port->next;
        }
+       
+       // run the cycle timers, get the suggested sleeo time
+       // until the next timer is due
        avr_cycle_count_t sleep = avr_cycle_timer_process(avr);
 
        avr->pc = new_pc;
@@ -177,22 +181,13 @@ int avr_run(avr_t * avr)
                        usleep(usec);
                avr->cycle += 1 + sleep;
        }
-       // Interrupt servicing might change the PC too
-       if (avr->state == cpu_Running || avr->state == cpu_Sleeping) {
+       // Interrupt servicing might change the PC too, during 'sleep'
+       if (avr->state == cpu_Running || avr->state == cpu_Sleeping)
                avr_service_interrupts(avr);
-
-               avr->data[R_SREG] = 0;
-               for (int i = 0; i < 8; i++)
-                       if (avr->sreg[i] > 1) {
-                               printf("** Invalid SREG!!\n");
-                               CRASH();
-                       } else if (avr->sreg[i])
-                               avr->data[R_SREG] |= (1 << i);
-       }
-
-       if (step) {
+       
+       // if we were stepping, use this state to inform remote gdb
+       if (step)
                avr->state = cpu_StepDone;
-       }
 
        return avr->state;
 }
index 663a57f..9c2256d 100644 (file)
@@ -99,6 +99,7 @@ typedef struct avr_t {
        // in the opcode decoder.
        // This array is re-synthetized back/forth when SREG changes
        uint8_t         sreg[8];
+       uint8_t         i_shadow;       // used to detect edges on I flag
 
        /* 
         * ** current PC **
index a8df91d..31c2ab3 100644 (file)
@@ -130,10 +130,10 @@ static inline void _avr_set_r(avr_t * avr, uint8_t r, uint8_t v)
        REG_TOUCH(avr, r);
 
        if (r == R_SREG) {
-               avr->data[r] = v;
+               avr->data[R_SREG] = v;
                // unsplit the SREG
                for (int i = 0; i < 8; i++)
-                       avr->sreg[i] = (avr->data[R_SREG] & (1 << i)) != 0;
+                       avr->sreg[i] = (v & (1 << i)) != 0;
                SREG();
        }
        if (r > 31) {
@@ -181,8 +181,22 @@ static inline void _avr_set_ram(avr_t * avr, uint16_t addr, uint8_t v)
  */
 static inline uint8_t _avr_get_ram(avr_t * avr, uint16_t addr)
 {
-       if (addr > 31 && addr < 256) {
+       if (addr == R_SREG) {
+               /*
+                * SREG is special it's reconstructed when read
+                * while the core itself uses the "shortcut" array
+                */
+               avr->data[R_SREG] = 0;
+               for (int i = 0; i < 8; i++)
+                       if (avr->sreg[i] > 1) {
+                               printf("** Invalid SREG!!\n");
+                               CRASH();
+                       } else if (avr->sreg[i])
+                               avr->data[R_SREG] |= (1 << i);
+               
+       } else if (addr > 31 && addr < 256) {
                uint8_t io = AVR_DATA_TO_IO(addr);
+               
                if (avr->io[io].r.c)
                        avr->data[addr] = avr->io[io].r.c(avr, addr, avr->io[io].r.param);
                
@@ -301,7 +315,7 @@ void avr_dump_state(avr_t * avr)
 #define get_r_d_10(o) \
                const uint8_t r = ((o >> 5) & 0x10) | (o & 0xf); \
                const uint8_t d = (o >> 4) & 0x1f;\
-               const uint8_t vd = avr->data[d], vr =avr->data[r];
+               const uint8_t vd = avr->data[d], vr = avr->data[r];
 #define get_k_r16(o) \
                const uint8_t r = 16 + ((o >> 4) & 0xf); \
                const uint8_t k = ((o & 0x0f00) >> 4) | (o & 0xf);
@@ -1197,15 +1211,12 @@ uint16_t avr_run_one(avr_t * avr)
                                        uint8_t r = (opcode >> 4) & 0x1f;
                                        uint8_t A = ((((opcode >> 9) & 3) << 4) | ((opcode) & 0xf)) + 32;
                                        STATE("out %s, %s[%02x]\n", avr_regname(A), avr_regname(r), avr->data[r]);
-                                       // todo: store to IO register
                                        _avr_set_ram(avr, A, avr->data[r]);
-                               //      avr->data[A] = ;
                                }       break;
                                case 0xb000: {  // IN Rd,A 1011 0AAr rrrr AAAA
                                        uint8_t r = (opcode >> 4) & 0x1f;
                                        uint8_t A = ((((opcode >> 9) & 3) << 4) | ((opcode) & 0xf)) + 32;
                                        STATE("in %s, %s[%02x]\n", avr_regname(r), avr_regname(A), avr->data[A]);
-                                       // todo: get the IO register
                                        _avr_set_r(avr, r, _avr_get_ram(avr, A));
                                }       break;
                                default: _avr_invalid_opcode(avr);