Skip to content

Commit c6343c1

Browse files
Add ATtiny1634 core support (#568)
* Add ATtiny1634 core support ATtiny1634 specifications: - 16KB Flash, 1KB SRAM, 256B EEPROM - 3 GPIO ports (A: 8 pins, B: 4 pins, C: 6 pins) - Timer0: 8-bit with PWM on OC0A (PC0), OC0B (PA5) - Timer1: 16-bit with PWM on OC1A (PB3), OC1B (PA6) - 12-channel 10-bit ADC with temperature sensor - Watchdog timer, PCINT on all 3 ports Note: ATtiny1634 has no WDCE bit so watchdog is declared manually without the timed sequence requirement. * Fix ATtiny1634 interrupt vector size (16KB flash needs 4-byte vectors) ATtiny1634 has 16KB flash, which requires the use of 4-byte JMP instructions in the interrupt vector table (RJMP cannot reach the full address space). This was causing the emulator to jump to wrong addresses when servicing interrupts. Also improved the interrupt stack overflow error message to include the vector number for easier debugging. --------- Co-authored-by: Ian Dobbie <[email protected]>
1 parent b3b4a4f commit c6343c1

File tree

3 files changed

+377
-1
lines changed

3 files changed

+377
-1
lines changed

simavr/cores/sim_tiny1634.c

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
sim_tiny1634.c
3+
4+
Copyright 2024 Ian Dobbie <[email protected]>
5+
6+
This file is part of simavr.
7+
8+
simavr is free software: you can redistribute it and/or modify
9+
it under the terms of the GNU General Public License as published by
10+
the Free Software Foundation, either version 3 of the License, or
11+
(at your option) any later version.
12+
13+
simavr is distributed in the hope that it will be useful,
14+
but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
GNU General Public License for more details.
17+
18+
You should have received a copy of the GNU General Public License
19+
along with simavr. If not, see <http://www.gnu.org/licenses/>.
20+
*/
21+
22+
#include "sim_avr.h"
23+
24+
#define SIM_VECTOR_SIZE 4 // 4-byte vectors for 16KB flash (needs JMP, not RJMP)
25+
#define SIM_MMCU "attiny1634"
26+
#define SIM_CORENAME mcu_tiny1634
27+
28+
#define _AVR_IO_H_
29+
#define __ASSEMBLER__
30+
#include "avr/iotn1634.h"
31+
32+
#include "sim_tiny1634.h"
33+
34+
static avr_t * make(void)
35+
{
36+
return avr_core_allocate(&SIM_CORENAME.core, sizeof(struct mcu_t));
37+
}
38+
39+
avr_kind_t tiny1634 = {
40+
.names = { "attiny1634" },
41+
.make = make
42+
};
43+
44+
void tn1634_init(struct avr_t * avr)
45+
{
46+
struct mcu_t * mcu = (struct mcu_t*)avr;
47+
48+
avr_eeprom_init(avr, &mcu->eeprom);
49+
avr_flash_init(avr, &mcu->selfprog);
50+
avr_watchdog_init(avr, &mcu->watchdog);
51+
avr_extint_init(avr, &mcu->extint);
52+
avr_ioport_init(avr, &mcu->porta);
53+
avr_ioport_init(avr, &mcu->portb);
54+
avr_ioport_init(avr, &mcu->portc);
55+
avr_adc_init(avr, &mcu->adc);
56+
avr_timer_init(avr, &mcu->timer0);
57+
avr_timer_init(avr, &mcu->timer1);
58+
}
59+
60+
void tn1634_reset(struct avr_t * avr)
61+
{
62+
// struct mcu_t * mcu = (struct mcu_t*)avr;
63+
}

simavr/cores/sim_tiny1634.h

Lines changed: 313 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,313 @@
1+
/*
2+
sim_tiny1634.h
3+
4+
Copyright 2024 Ian Dobbie <[email protected]>
5+
6+
This file is part of simavr.
7+
8+
simavr is free software: you can redistribute it and/or modify
9+
it under the terms of the GNU General Public License as published by
10+
the Free Software Foundation, either version 3 of the License, or
11+
(at your option) any later version.
12+
13+
simavr is distributed in the hope that it will be useful,
14+
but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
GNU General Public License for more details.
17+
18+
You should have received a copy of the GNU General Public License
19+
along with simavr. If not, see <http://www.gnu.org/licenses/>.
20+
*/
21+
22+
/*
23+
* ATtiny1634 specifications:
24+
* - 16KB Flash, 1KB SRAM, 256B EEPROM
25+
* - 3 GPIO ports (A: 8 pins, B: 4 pins, C: 6 pins)
26+
* - Timer0: 8-bit with PWM on OC0A (PC0), OC0B (PA5)
27+
* - Timer1: 16-bit with PWM on OC1A (PB3), OC1B (PA6)
28+
* - 12-channel 10-bit ADC
29+
* - WDT, PCINT on all 3 ports
30+
*/
31+
32+
#ifndef __SIM_TINY1634_H__
33+
#define __SIM_TINY1634_H__
34+
35+
#include "sim_core_declare.h"
36+
#include "avr_eeprom.h"
37+
#include "avr_flash.h"
38+
#include "avr_watchdog.h"
39+
#include "avr_extint.h"
40+
#include "avr_ioport.h"
41+
#include "avr_timer.h"
42+
#include "avr_adc.h"
43+
44+
void tn1634_init(struct avr_t * avr);
45+
void tn1634_reset(struct avr_t * avr);
46+
47+
/*
48+
* ATtiny1634 MCU structure
49+
* Note: No UART/USI in this implementation - add as needed
50+
*/
51+
struct mcu_t {
52+
avr_t core;
53+
avr_eeprom_t eeprom;
54+
avr_flash_t selfprog;
55+
avr_watchdog_t watchdog;
56+
avr_extint_t extint;
57+
avr_ioport_t porta, portb, portc;
58+
avr_timer_t timer0, timer1;
59+
avr_adc_t adc;
60+
};
61+
62+
#ifdef SIM_CORENAME
63+
64+
#ifndef SIM_VECTOR_SIZE
65+
#error SIM_VECTOR_SIZE is not declared
66+
#endif
67+
#ifndef SIM_MMCU
68+
#error SIM_MMCU is not declared
69+
#endif
70+
71+
const struct mcu_t SIM_CORENAME = {
72+
.core = {
73+
.mmcu = SIM_MMCU,
74+
DEFAULT_CORE(SIM_VECTOR_SIZE),
75+
76+
.init = tn1634_init,
77+
.reset = tn1634_reset,
78+
},
79+
AVR_EEPROM_DECLARE(EE_RDY_vect),
80+
// ATtiny1634 has no WDCE bit - simavr still needs a valid register for wdce
81+
// Point wdce to WDTCSR bit 4 (unused) to satisfy simavr's init
82+
.watchdog = {
83+
.wdrf = AVR_IO_REGBIT(MCUSR, WDRF),
84+
.wdce = AVR_IO_REGBIT(WDTCSR, 4), // Dummy - bit 4 is unused in ATtiny1634
85+
.wde = AVR_IO_REGBIT(WDTCSR, WDE),
86+
.wdp = { AVR_IO_REGBIT(WDTCSR, WDP0), AVR_IO_REGBIT(WDTCSR, WDP1),
87+
AVR_IO_REGBIT(WDTCSR, WDP2), AVR_IO_REGBIT(WDTCSR, WDP3) },
88+
.watchdog = {
89+
.enable = AVR_IO_REGBIT(WDTCSR, WDIE),
90+
.raised = AVR_IO_REGBIT(WDTCSR, WDIF),
91+
.vector = WDT_vect,
92+
},
93+
},
94+
.selfprog = {
95+
.flags = 0,
96+
.r_spm = SPMCSR,
97+
.spm_pagesize = SPM_PAGESIZE,
98+
.selfprgen = AVR_IO_REGBIT(SPMCSR, SPMEN),
99+
.pgers = AVR_IO_REGBIT(SPMCSR, PGERS),
100+
.pgwrt = AVR_IO_REGBIT(SPMCSR, PGWRT),
101+
.blbset = AVR_IO_REGBIT(SPMCSR, RFLB),
102+
},
103+
.extint = {
104+
AVR_EXTINT_TINY_DECLARE(0, 'A', 2, GIFR),
105+
},
106+
.porta = {
107+
.name = 'A', .r_port = PORTA, .r_ddr = DDRA, .r_pin = PINA,
108+
.pcint = {
109+
.enable = AVR_IO_REGBIT(GIMSK, PCIE0),
110+
.raised = AVR_IO_REGBIT(GIFR, PCIF0),
111+
.vector = PCINT0_vect,
112+
},
113+
.r_pcint = PCMSK0,
114+
},
115+
.portb = {
116+
.name = 'B', .r_port = PORTB, .r_ddr = DDRB, .r_pin = PINB,
117+
.pcint = {
118+
.enable = AVR_IO_REGBIT(GIMSK, PCIE1),
119+
.raised = AVR_IO_REGBIT(GIFR, PCIF1),
120+
.vector = PCINT1_vect,
121+
},
122+
.r_pcint = PCMSK1,
123+
},
124+
.portc = {
125+
.name = 'C', .r_port = PORTC, .r_ddr = DDRC, .r_pin = PINC,
126+
.pcint = {
127+
.enable = AVR_IO_REGBIT(GIMSK, PCIE2),
128+
.raised = AVR_IO_REGBIT(GIFR, PCIF2),
129+
.vector = PCINT2_vect,
130+
},
131+
.r_pcint = PCMSK2,
132+
},
133+
134+
// Timer0 - 8-bit with PWM on OC0A (PC0) and OC0B (PA5)
135+
.timer0 = {
136+
.name = '0',
137+
.disabled = AVR_IO_REGBIT(PRR, PRTIM0),
138+
.wgm = { AVR_IO_REGBIT(TCCR0A, WGM00), AVR_IO_REGBIT(TCCR0A, WGM01),
139+
AVR_IO_REGBIT(TCCR0B, WGM02) },
140+
.wgm_op = {
141+
[0] = AVR_TIMER_WGM_NORMAL8(),
142+
[1] = AVR_TIMER_WGM_FCPWM8(),
143+
[2] = AVR_TIMER_WGM_CTC(),
144+
[3] = AVR_TIMER_WGM_FASTPWM8(),
145+
[5] = AVR_TIMER_WGM_OCPWM(),
146+
[7] = { .kind = avr_timer_wgm_fast_pwm, .top = avr_timer_wgm_reg_ocra },
147+
},
148+
.cs = { AVR_IO_REGBIT(TCCR0B, CS00), AVR_IO_REGBIT(TCCR0B, CS01),
149+
AVR_IO_REGBIT(TCCR0B, CS02) },
150+
.cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */,
151+
AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE },
152+
153+
.r_tcnt = TCNT0,
154+
155+
.overflow = {
156+
.enable = AVR_IO_REGBIT(TIMSK, TOIE0),
157+
.raised = AVR_IO_REGBIT(TIFR, TOV0),
158+
.vector = TIM0_OVF_vect,
159+
},
160+
.comp = {
161+
[AVR_TIMER_COMPA] = {
162+
.r_ocr = OCR0A,
163+
.com = AVR_IO_REGBITS(TCCR0A, COM0A0, 0x3),
164+
.com_pin = AVR_IO_REGBIT(PORTC, 0),
165+
.interrupt = {
166+
.enable = AVR_IO_REGBIT(TIMSK, OCIE0A),
167+
.raised = AVR_IO_REGBIT(TIFR, OCF0A),
168+
.vector = TIM0_COMPA_vect,
169+
},
170+
},
171+
[AVR_TIMER_COMPB] = {
172+
.r_ocr = OCR0B,
173+
.com = AVR_IO_REGBITS(TCCR0A, COM0B0, 0x3),
174+
.com_pin = AVR_IO_REGBIT(PORTA, 5),
175+
.interrupt = {
176+
.enable = AVR_IO_REGBIT(TIMSK, OCIE0B),
177+
.raised = AVR_IO_REGBIT(TIFR, OCF0B),
178+
.vector = TIM0_COMPB_vect,
179+
},
180+
},
181+
},
182+
},
183+
184+
// Timer1 - 16-bit with PWM on OC1A (PB3) and OC1B (PA6)
185+
.timer1 = {
186+
.name = '1',
187+
.disabled = AVR_IO_REGBIT(PRR, PRTIM1),
188+
.wgm = { AVR_IO_REGBIT(TCCR1A, WGM10), AVR_IO_REGBIT(TCCR1A, WGM11),
189+
AVR_IO_REGBIT(TCCR1B, WGM12), AVR_IO_REGBIT(TCCR1B, WGM13) },
190+
.wgm_op = {
191+
[0] = AVR_TIMER_WGM_NORMAL16(),
192+
[1] = AVR_TIMER_WGM_FCPWM8(),
193+
[2] = AVR_TIMER_WGM_FCPWM9(),
194+
[3] = AVR_TIMER_WGM_FCPWM10(),
195+
[4] = AVR_TIMER_WGM_CTC(),
196+
[5] = AVR_TIMER_WGM_FASTPWM8(),
197+
[6] = AVR_TIMER_WGM_FASTPWM9(),
198+
[7] = AVR_TIMER_WGM_FASTPWM10(),
199+
[8] = AVR_TIMER_WGM_ICPWM(),
200+
[9] = AVR_TIMER_WGM_OCPWM(),
201+
[10] = AVR_TIMER_WGM_ICPWM(),
202+
[11] = AVR_TIMER_WGM_OCPWM(),
203+
[12] = AVR_TIMER_WGM_ICCTC(),
204+
[14] = AVR_TIMER_WGM_ICFASTPWM(),
205+
[15] = { .kind = avr_timer_wgm_fast_pwm, .top = avr_timer_wgm_reg_ocra },
206+
},
207+
.cs = { AVR_IO_REGBIT(TCCR1B, CS10), AVR_IO_REGBIT(TCCR1B, CS11),
208+
AVR_IO_REGBIT(TCCR1B, CS12) },
209+
.cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */,
210+
AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE },
211+
212+
.r_tcnt = TCNT1L,
213+
.r_tcnth = TCNT1H,
214+
.r_icr = ICR1L,
215+
.r_icrh = ICR1H,
216+
217+
.ices = AVR_IO_REGBIT(TCCR1B, ICES1),
218+
.icp = AVR_IO_REGBIT(PORTB, 1), /* ICP1 on PB1 */
219+
220+
.overflow = {
221+
.enable = AVR_IO_REGBIT(TIMSK, TOIE1),
222+
.raised = AVR_IO_REGBIT(TIFR, TOV1),
223+
.vector = TIM1_OVF_vect,
224+
},
225+
.icr = {
226+
.enable = AVR_IO_REGBIT(TIMSK, ICIE1),
227+
.raised = AVR_IO_REGBIT(TIFR, ICF1),
228+
.vector = TIM1_CAPT_vect,
229+
},
230+
.comp = {
231+
[AVR_TIMER_COMPA] = {
232+
.r_ocr = OCR1AL,
233+
.r_ocrh = OCR1AH,
234+
.com = AVR_IO_REGBITS(TCCR1A, COM1A0, 0x3),
235+
.com_pin = AVR_IO_REGBIT(PORTB, 3),
236+
.interrupt = {
237+
.enable = AVR_IO_REGBIT(TIMSK, OCIE1A),
238+
.raised = AVR_IO_REGBIT(TIFR, OCF1A),
239+
.vector = TIM1_COMPA_vect,
240+
},
241+
},
242+
[AVR_TIMER_COMPB] = {
243+
.r_ocr = OCR1BL,
244+
.r_ocrh = OCR1BH,
245+
.com = AVR_IO_REGBITS(TCCR1A, COM1B0, 0x3),
246+
.com_pin = AVR_IO_REGBIT(PORTA, 6),
247+
.interrupt = {
248+
.enable = AVR_IO_REGBIT(TIMSK, OCIE1B),
249+
.raised = AVR_IO_REGBIT(TIFR, OCF1B),
250+
.vector = TIM1_COMPB_vect,
251+
},
252+
},
253+
},
254+
},
255+
256+
// ADC - 12 channels, 10-bit
257+
.adc = {
258+
.r_admux = ADMUX,
259+
.mux = { AVR_IO_REGBIT(ADMUX, MUX0), AVR_IO_REGBIT(ADMUX, MUX1),
260+
AVR_IO_REGBIT(ADMUX, MUX2), AVR_IO_REGBIT(ADMUX, MUX3) },
261+
.ref = { AVR_IO_REGBIT(ADMUX, REFS0), AVR_IO_REGBIT(ADMUX, REFS1) },
262+
.ref_values = {
263+
[0] = ADC_VREF_VCC,
264+
[1] = ADC_VREF_V110,
265+
},
266+
267+
.adlar = AVR_IO_REGBIT(ADCSRB, ADLAR),
268+
.r_adcsra = ADCSRA,
269+
.aden = AVR_IO_REGBIT(ADCSRA, ADEN),
270+
.adsc = AVR_IO_REGBIT(ADCSRA, ADSC),
271+
.adate = AVR_IO_REGBIT(ADCSRA, ADATE),
272+
.adps = { AVR_IO_REGBIT(ADCSRA, ADPS0), AVR_IO_REGBIT(ADCSRA, ADPS1),
273+
AVR_IO_REGBIT(ADCSRA, ADPS2) },
274+
275+
.r_adch = ADCH,
276+
.r_adcl = ADCL,
277+
278+
.r_adcsrb = ADCSRB,
279+
.adts = { AVR_IO_REGBIT(ADCSRB, ADTS0), AVR_IO_REGBIT(ADCSRB, ADTS1),
280+
AVR_IO_REGBIT(ADCSRB, ADTS2) },
281+
.adts_op = {
282+
[0] = avr_adts_free_running,
283+
[1] = avr_adts_analog_comparator_0,
284+
[2] = avr_adts_external_interrupt_0,
285+
[3] = avr_adts_timer_0_compare_match_a,
286+
[4] = avr_adts_timer_0_overflow,
287+
[5] = avr_adts_timer_1_compare_match_b,
288+
[6] = avr_adts_timer_1_overflow,
289+
[7] = avr_adts_timer_1_capture_event,
290+
},
291+
292+
.muxmode = {
293+
[0] = AVR_ADC_SINGLE(0), [1] = AVR_ADC_SINGLE(1),
294+
[2] = AVR_ADC_SINGLE(2), [3] = AVR_ADC_SINGLE(3),
295+
[4] = AVR_ADC_SINGLE(4), [5] = AVR_ADC_SINGLE(5),
296+
[6] = AVR_ADC_SINGLE(6), [7] = AVR_ADC_SINGLE(7),
297+
[8] = AVR_ADC_SINGLE(8), [9] = AVR_ADC_SINGLE(9),
298+
[10] = AVR_ADC_SINGLE(10), [11] = AVR_ADC_SINGLE(11),
299+
[14] = AVR_ADC_TEMP(),
300+
[15] = AVR_ADC_REF(0), // 0V (GND)
301+
},
302+
303+
.adc = {
304+
.enable = AVR_IO_REGBIT(ADCSRA, ADIE),
305+
.raised = AVR_IO_REGBIT(ADCSRA, ADIF),
306+
.vector = ADC_vect,
307+
},
308+
},
309+
};
310+
311+
#endif /* SIM_CORENAME */
312+
313+
#endif /* __SIM_TINY1634_H__ */

simavr/sim/sim_interrupts.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ avr_service_interrupts(
286286
avr_raise_irq(vector->irq + AVR_INT_IRQ_RUNNING, 1);
287287
avr_raise_irq(table->irq + AVR_INT_IRQ_RUNNING, vector->vector);
288288
if (table->running_ptr == ARRAY_SIZE(table->running)) {
289-
AVR_LOG(avr, LOG_ERROR, "%s run out of nested stack!", __func__);
289+
AVR_LOG(avr, LOG_ERROR, "%s run out of nested stack! vector=%d", __func__, vector->vector);
290290
} else {
291291
table->running[table->running_ptr++] = vector;
292292
}

0 commit comments

Comments
 (0)