Total rework of simulator for dev branch. Create separate thread for interrupt processes. Tick-accurate simulation of timers. Non-blocking character input for running in realtime mode. Decouple hardware sim from grbl code as much as possible. Expanded command line options. Provisions for cross-platform solution.

This commit is contained in:
ashelly
2014-07-04 11:14:54 -04:00
parent 92d6c2bca5
commit 8c9f3bca65
33 changed files with 1062 additions and 437 deletions

View File

@ -21,23 +21,115 @@
*/
#include "interrupt.h"
#include "io.h"
//pseudo-Interrupt vector table
isr_fp compa_vect[6]={0};
isr_fp compb_vect[6]={0};
isr_fp ovf_vect[6]={0};
void sei() {io.sreg|=SEI;}
void cli() {io.sreg&=~SEI;}
int16_t sim_scaling[8]={0,1,8,64,256,1024,1,1}; //clock scalars
//Timer/Counter modes: these are incomplete, but enough for this application
enum sim_wgm_mode {
wgm_NORMAL,
wgm_CTC,
wgm_FAST_PWM,
wgm_PHASE_PWM,
wgm_PH_F_PWM,
wgm_RESERVED
};
enum sim_wgm_mode sim_wgm0[4] = {wgm_NORMAL,wgm_PHASE_PWM,wgm_CTC,wgm_FAST_PWM};
enum sim_wgm_mode sim_wgmN[8] = {wgm_NORMAL,wgm_PHASE_PWM,wgm_PHASE_PWM,wgm_PH_F_PWM,
wgm_CTC, wgm_FAST_PWM, wgm_FAST_PWM, wgm_FAST_PWM};
void timer_interrupts() {
int i;
uint8_t ien = io.sreg&SEI; //interrupts enabled?
io.prescaler++;
//all clocks
for (i=0;i<2;i++){
uint8_t cs = io.tccrb[i]&7; //clock select bits
int16_t increment = sim_scaling[cs];
//check scaling to see if timer fires
if (increment && (io.prescaler&(increment-1))==0) {
//select waveform generation mode
enum sim_wgm_mode mode;
if (i==0 || i==2) { //(T0 and T2 are different from rest)
uint8_t wgm = io.tccra[i]&3; //look at low 2 bits
mode = sim_wgm0[wgm];
}
else {
uint8_t wgm = ((io.tccrb[i]&8)>>1) | (io.tccra[i]&3); //only using 3 bits for now
mode = sim_wgmN[wgm];
}
//tick
io.tcnt[i]++;
//comparators
if ((io.timsk[i]&(1<<SIM_OCA)) && io.tcnt[i]==io.ocra[i]) io.tifr[i]|=(1<<SIM_OCA);
if ((io.timsk[i]&(1<<SIM_OCB)) && io.tcnt[i]==io.ocrb[i]) io.tifr[i]|=(1<<SIM_OCB);
if ((io.timsk[i]&(1<<SIM_OCC)) && io.tcnt[i]==io.ocrc[i]) io.tifr[i]|=(1<<SIM_OCC);
switch (mode) {
case wgm_NORMAL: //Normal mode
if (i==0) io.tcnt[i]&=0xFF; //timer0 is 8 bit;
if (i==2) io.tcnt[i]&=0xFF; //timer2 is 8 bit;
if (io.tcnt[i]==0) io.tifr[i]|=(1<<SIM_TOV);
break;
case wgm_CTC: //CTC mode
if (io.tcnt[i]==io.ocra[i]) io.tcnt[i]=0;
break;
default: //unsupported
break;
}
//call any triggered interupts
if (ien && io.tifr[i]) {
if (compa_vect[i] && (io.tifr[i]&(1<<SIM_OCA))) {
compa_vect[i]();
io.tifr[i]&=~(1<<SIM_OCA);
//TODO: insert port_monitor call here
}
if (compb_vect[i] && (io.tifr[i]&(1<<SIM_OCB))) {
compb_vect[i]();
io.tifr[i]&=~(1<<SIM_OCB);
}
if (ovf_vect[i] && (io.tifr[i]&(1<<SIM_TOV))) {
ovf_vect[i]();
io.tifr[i]&=~(1<<SIM_TOV);
}
}
}
}
//// TODO for more complete timer sim.
// pwm modes. (only used for variable spindle, I think).
// -- would require fixing wgm mode for Timers1..5
// -- phase correct modes need updown counter.
// output pins (also only for variable spindle, I think).
//// Other chip features not needed yet for grbl:
// writes to TCNT0 prevent compare match (need write detector.)
// force output compare (unused)
// input capture (unused and how would we signal it?)
// define the other output compare registers.
// usercode can clear unhandled interrupt flags by writing 1.
// --(this may be impossible, since bit was 1 before the write.)
// prescaler reset.
// maybe need to cli on interrupt entry
}
// dummy register variables
uint16_t timsk0;
uint16_t timsk1;
uint16_t timsk2;
uint16_t ocr1a;
uint16_t ocr2a;
uint16_t tcnt0;
uint16_t tcnt2;
uint16_t tccr0b;
uint16_t tccr2b;
uint16_t tccr1b;
uint16_t tccr0a;
uint16_t tccr1a;
uint16_t tccr2a;
uint16_t pcmsk0;
uint16_t pcicr;
void sei() {};
void cli() {};

View File

@ -24,60 +24,33 @@
#ifndef interrupt_h
#define interrupt_h
#include <inttypes.h>
// dummy register variables
extern uint16_t timsk0;
extern uint16_t timsk1;
extern uint16_t timsk2;
extern uint16_t tcnt0;
extern uint16_t tcnt2;
extern uint16_t tccr0b;
extern uint16_t tccr0a;
extern uint16_t tccr2a;
extern uint16_t tccr2b;
extern uint16_t tccr1b;
extern uint16_t tccr1a;
extern uint16_t ocr1a;
extern uint16_t ocr2a;
extern uint16_t pcmsk0;
extern uint16_t pcicr;
// macros to turn avr interrupts into regular functions
#define TIMER1_COMPA_vect
//#define TIMER1_COMPA_vect
#define ISR(a) void interrupt_ ## a ()
// enable interrupts does nothing in the simulation environment
// Stub of the timer interrupt functions we need
void interrupt_TIMER0_COMPA_vect();
void interrupt_TIMER1_COMPA_vect();
void interrupt_TIMER0_OVF_vect();
void interrupt_SERIAL_UDRE();
void interrupt_SERIAL_RX();
//pseudo-Interrupt vector table
typedef void(*isr_fp)(void);
extern isr_fp compa_vect[6];
extern isr_fp compb_vect[6];
extern isr_fp ovf_vect[6];
// enable interrupts now does something in the simulation environment
#define SEI 0x80
void sei();
void cli();
// dummy macros for interrupt related registers
#define TIMSK0 timsk0
#define TIMSK1 timsk1
#define TIMSK2 timsk2
#define OCR1A ocr1a
#define OCR2A ocr2a
#define OCIE1A 0
#define OCIE2A 0
#define TCNT0 tcnt0
#define TCNT2 tcnt2
#define TCCR0B tccr0b
#define TCCR0A tccr0a
#define TCCR1A tccr1a
#define TCCR1B tccr1b
#define TCCR2A tccr2a
#define TCCR2B tccr2b
#define CS21 0
#define CS10 0
#define WGM13 0
#define WGM12 0
#define WGM11 0
#define WGM10 0
#define WGM21 0
#define COM1A0 0
#define COM1B0 0
#define TOIE0 0
#define TOIE2 0
#define PCICR pcicr
//simulate timer operation
void timer_interrupts();
#endif

4
sim/avr/io.c Normal file
View File

@ -0,0 +1,4 @@
#include "io.h"
// dummy register variables
volatile io_sim_t io={{0}};

View File

@ -1,5 +1,6 @@
/*
io.h - dummy replacement for the avr include of the same name
interrupt.h - replacement for the avr include of the same name to provide
dummy register variables and macros
Part of Grbl Simulator
@ -19,3 +20,182 @@
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef io_h
#define io_h
#include <inttypes.h>
union hilo16 {
uint16_t w;
struct {
uint8_t l; //TODO: check that these are right order on x86. Doesn't matter for current usage, but might someday
uint8_t h;
};
};
enum {
SIM_A, SIM_B, SIM_C, SIM_D, SIM_E,
SIM_F, SIM_G, SIM_H, SIM_J, SIM_K, SIM_L,
SIM_PORT_COUNT
};
#define SIM_N_TIMERS 6
// dummy register variables
typedef struct io_sim {
uint8_t ddr[SIM_PORT_COUNT];
uint8_t port[SIM_PORT_COUNT];
uint8_t pin[SIM_PORT_COUNT];
uint8_t timsk[SIM_N_TIMERS];
uint16_t ocra[SIM_N_TIMERS];
uint16_t ocrb[SIM_N_TIMERS];
uint16_t ocrc[SIM_N_TIMERS];
uint16_t tcnt[SIM_N_TIMERS]; //tcint0 is really only 8bit
uint8_t tccra[SIM_N_TIMERS];
uint8_t tccrb[SIM_N_TIMERS];
uint8_t tifr[SIM_N_TIMERS];
uint8_t pcicr;
uint8_t pcmsk[3];
uint8_t ucsr0[3];
uint8_t udr[3];
union hilo16 ubrr0;
uint16_t prescaler; //continuously running
uint8_t sreg;
} io_sim_t;
volatile extern io_sim_t io;
// dummy macros for interrupt related registers
#define PORTA io.port[SIM_A]
#define PORTB io.port[SIM_B]
#define PORTC io.port[SIM_C]
#define PORTD io.port[SIM_D]
#define PORTE io.port[SIM_E]
#define PORTF io.port[SIM_F]
#define PORTG io.port[SIM_G]
#define PORTH io.port[SIM_H]
#define PORTJ io.port[SIM_J]
#define PORTK io.port[SIM_K]
#define PORTL io.port[SIM_L]
#define DDRA io.ddr[SIM_A]
#define DDRB io.ddr[SIM_B]
#define DDRC io.ddr[SIM_C]
#define DDRD io.ddr[SIM_D]
#define DDRE io.ddr[SIM_E]
#define DDRF io.ddr[SIM_F]
#define DDRG io.ddr[SIM_G]
#define DDRH io.ddr[SIM_H]
#define DDRJ io.ddr[SIM_J]
#define PINA io.pin[SIM_A]
#define PINB io.pin[SIM_B]
#define PINC io.pin[SIM_C]
#define PIND io.pin[SIM_D]
#define PINE io.pin[SIM_E]
#define PINF io.pin[SIM_F]
#define PING io.pin[SIM_G]
#define PINH io.pin[SIM_H]
#define PINJ io.pin[SIM_J]
#define PINK io.pin[SIM_K]
#define PINL io.pin[SIM_L]
#define TIMSK0 io.timsk[0]
#define TIMSK1 io.timsk[1]
#define TIMSK2 io.timsk[2]
#define TIMSK3 io.timsk[3]
#define TIMSK4 io.timsk[4]
#define TIMSK5 io.timsk[5]
#define SIM_TOV 0
#define SIM_OCA 1
#define SIM_OCB 2
#define SIM_OCC 3
#define SIM_ICI 5
#define OCIE0A SIM_OCA
#define OCIE0B SIM_OCB
#define TOIE0 SIM_TOV
#define ICIE1 SIM_ICI
#define OCIE1C SIM_OCC
#define OCIE1B SIM_OCB
#define OCIE1A SIM_OCA
#define TOIE1 SIM_ICI
#define ICIE2 SIM_ICI
#define OCIE2C SIM_OCC
#define OCIE2B SIM_OCB
#define OCIE2A SIM_OCA
#define TOIE2 SIM_TOV
#define OCR0A io.ocra[0]
#define OCR1A io.ocra[1]
#define OCR2A io.ocra[2]
//There are more..
#define TCNT0 io.tcnt[0]
#define TCNT1 io.tcnt[1]
#define TCNT2 io.tcnt[2]
#define TCCR0B io.tccra[0]
#define TCCR0A io.tccrb[0]
#define TCCR1A io.tccra[1]
#define TCCR1B io.tccrb[1]
#define TCCR2A io.tccra[2]
#define TCCR2B io.tccrb[2]
#define CS00 0
#define CS01 1
#define CS12 2
#define CS11 1
#define CS10 0
#define CS21 1
#define WGM13 4
#define WGM12 3
#define WGM11 1
#define WGM10 0
#define WGM21 1
#define COM1A1 7
#define COM1A0 6
#define COM1B1 5
#define COM1B0 4
#define COM1C1 3
#define COM1C0 2
#define PCICR io.pcicr
#define PCIE0 0
#define PCIE1 1
//serial channel
#define UCSR0A io.ucsr0[SIM_A]
#define UCSR0B io.ucsr0[SIM_B]
#define UDR0 io.udr[0]
#define UDRIE0 0
#define RXCIE0 1
#define RXEN0 2
#define TXEN0 3
#define U2X0 4
#define UBRR0H io.ubrr0.h
#define UBRR0L io.ubrr0.l
#define PCMSK0 io.pcmsk[0]
#define PCMSK1 io.pcmsk[1]
#define PCMSK2 io.pcmsk[2]
#endif

1
sim/avr/wdt.h Normal file
View File

@ -0,0 +1 @@
uint16_t wdt;