diff --git a/build.zig b/build.zig index cb8771c..773efc6 100644 --- a/build.zig +++ b/build.zig @@ -31,7 +31,7 @@ pub fn build(b: *std.build.Builder) !void { Test{ .name = "uart-sync", .source = "tests/uart-sync.zig", .uses_uart = true, .on_avr = false }, // Note: this example uses the systick interrupt and therefore only for arm microcontrollers - Test{ .name = "interrupt", .source = "tests/interrupt.zig", .on_avr = false }, + Test{ .name = "interrupt", .source = "tests/interrupt.zig", .on_avr = true }, }; const filter = b.option(std.Target.Cpu.Arch, "filter-target", "Filters for a certain cpu target"); diff --git a/src/modules/chips/atmega328p/atmega328p.zig b/src/modules/chips/atmega328p/atmega328p.zig index b156c94..32ffbb6 100644 --- a/src/modules/chips/atmega328p/atmega328p.zig +++ b/src/modules/chips/atmega328p/atmega328p.zig @@ -1,5 +1,6 @@ const std = @import("std"); const micro = @import("microzig"); +pub usingnamespace @import("registers.zig"); pub const cpu = micro.cpu; const Port = enum(u8) { diff --git a/src/modules/chips/atmega328p/registers.zig b/src/modules/chips/atmega328p/registers.zig new file mode 100644 index 0000000..06d4880 --- /dev/null +++ b/src/modules/chips/atmega328p/registers.zig @@ -0,0 +1,1327 @@ +// this file was generated by regz: https://github.com/ZigEmbeddedGroup/regz +// commit: 6376709051af4d8920d5c8bb48945ca688af32ae +// +// vendor: Atmel +// device: ATmega328P +// cpu: AVR8 + +pub const VectorTable = extern struct { + /// External Pin, Power-on Reset, Brown-out Reset and Watchdog Reset + RESET: InterruptVector = unhandled, + /// External Interrupt Request 0 + INT0: InterruptVector = unhandled, + /// External Interrupt Request 1 + INT1: InterruptVector = unhandled, + /// Pin Change Interrupt Request 0 + PCINT0: InterruptVector = unhandled, + /// Pin Change Interrupt Request 1 + PCINT1: InterruptVector = unhandled, + /// Pin Change Interrupt Request 2 + PCINT2: InterruptVector = unhandled, + /// Watchdog Time-out Interrupt + WDT: InterruptVector = unhandled, + /// Timer/Counter2 Compare Match A + TIMER2_COMPA: InterruptVector = unhandled, + /// Timer/Counter2 Compare Match B + TIMER2_COMPB: InterruptVector = unhandled, + /// Timer/Counter2 Overflow + TIMER2_OVF: InterruptVector = unhandled, + /// Timer/Counter1 Capture Event + TIMER1_CAPT: InterruptVector = unhandled, + /// Timer/Counter1 Compare Match A + TIMER1_COMPA: InterruptVector = unhandled, + /// Timer/Counter1 Compare Match B + TIMER1_COMPB: InterruptVector = unhandled, + /// Timer/Counter1 Overflow + TIMER1_OVF: InterruptVector = unhandled, + /// TimerCounter0 Compare Match A + TIMER0_COMPA: InterruptVector = unhandled, + /// TimerCounter0 Compare Match B + TIMER0_COMPB: InterruptVector = unhandled, + /// Timer/Couner0 Overflow + TIMER0_OVF: InterruptVector = unhandled, + /// SPI Serial Transfer Complete + SPI_STC: InterruptVector = unhandled, + /// USART Rx Complete + USART_RX: InterruptVector = unhandled, + /// USART, Data Register Empty + USART_UDRE: InterruptVector = unhandled, + /// USART Tx Complete + USART_TX: InterruptVector = unhandled, + /// ADC Conversion Complete + ADC: InterruptVector = unhandled, + /// EEPROM Ready + EE_READY: InterruptVector = unhandled, + /// Analog Comparator + ANALOG_COMP: InterruptVector = unhandled, + /// Two-wire Serial Interface + TWI: InterruptVector = unhandled, + /// Store Program Memory Read + SPM_Ready: InterruptVector = unhandled, +}; + +pub const registers = struct { + + /// Fuses + pub const FUSE = struct { + + /// address: 0x2 + pub const EXTENDED = @intToPtr(*volatile Mmio(8, packed struct { + /// Brown-out Detector trigger level + /// + /// 0x4: Brown-out detection at VCC=4.3 V + /// 0x5: Brown-out detection at VCC=2.7 V + /// 0x6: Brown-out detection at VCC=1.8 V + /// 0x7: Brown-out detection disabled + BODLEVEL: u3, + padding0: u1, + padding1: u1, + padding2: u1, + padding3: u1, + padding4: u1, + }), 0x2); + + /// address: 0x1 + pub const HIGH = @intToPtr(*volatile Mmio(8, packed struct { + /// Boot Reset vector Enabled + BOOTRST: u1, + /// Select boot size + /// + /// 0x0: Boot Flash size=2048 words start address=$3800 + /// 0x1: Boot Flash size=1024 words start address=$3C00 + /// 0x2: Boot Flash size=512 words start address=$3E00 + /// 0x3: Boot Flash size=256 words start address=$3F00 + BOOTSZ: u2, + /// Preserve EEPROM through the Chip Erase cycle + EESAVE: u1, + /// Watch-dog Timer always on + WDTON: u1, + /// Serial program downloading (SPI) enabled + SPIEN: u1, + /// Debug Wire enable + DWEN: u1, + /// Reset Disabled (Enable PC6 as i/o pin) + RSTDISBL: u1, + }), 0x1); + + /// address: 0x0 + pub const LOW = @intToPtr(*volatile Mmio(8, packed struct { + /// Select Clock Source + /// + /// 0x0: Ext. Clock; Start-up time PWRDWN/RESET: 6 CK/14 CK + 0 ms + /// 0x2: Int. RC Osc. 8 MHz; Start-up time PWRDWN/RESET: 6 CK/14 CK + 0 ms + /// 0x3: Int. RC Osc. 128kHz; Start-up time PWRDWN/RESET: 6 CK/14 CK + 0 ms + /// 0x4: Ext. Low-Freq. Crystal; Start-up time PWRDWN/RESET: 1K CK/14 CK + 0 ms + /// 0x5: Ext. Low-Freq. Crystal; Start-up time PWRDWN/RESET: 32K CK/14 CK + 0 ms + /// 0x6: Ext. Full-swing Crystal; Start-up time PWRDWN/RESET: 258 CK/14 CK + 4.1 ms + /// 0x7: Ext. Full-swing Crystal; Start-up time PWRDWN/RESET: 1K CK /14 CK + 65 ms + /// 0x8: Ext. Crystal Osc. 0.4-0.9 MHz; Start-up time PWRDWN/RESET: 258 CK/14 CK + 4.1 ms + /// 0x9: Ext. Crystal Osc. 0.4-0.9 MHz; Start-up time PWRDWN/RESET: 1K CK /14 CK + 65 ms + /// 0xa: Ext. Crystal Osc. 0.9-3.0 MHz; Start-up time PWRDWN/RESET: 258 CK/14 CK + 4.1 ms + /// 0xb: Ext. Crystal Osc. 0.9-3.0 MHz; Start-up time PWRDWN/RESET: 1K CK /14 CK + 65 ms + /// 0xc: Ext. Crystal Osc. 3.0-8.0 MHz; Start-up time PWRDWN/RESET: 258 CK/14 CK + 4.1 ms + /// 0xd: Ext. Crystal Osc. 3.0-8.0 MHz; Start-up time PWRDWN/RESET: 1K CK /14 CK + 65 ms + /// 0xe: Ext. Crystal Osc. 8.0- MHz; Start-up time PWRDWN/RESET: 258 CK/14 CK + 4.1 ms + /// 0xf: Ext. Crystal Osc. 8.0- MHz; Start-up time PWRDWN/RESET: 1K CK /14 CK + 65 ms + /// 0x10: Ext. Clock; Start-up time PWRDWN/RESET: 6 CK/14 CK + 4.1 ms + /// 0x12: Int. RC Osc. 8 MHz; Start-up time PWRDWN/RESET: 6 CK/14 CK + 4.1 ms + /// 0x13: Int. RC Osc. 128kHz; Start-up time PWRDWN/RESET: 6 CK/14 CK + 4.1 ms + /// 0x14: Ext. Low-Freq. Crystal; Start-up time PWRDWN/RESET: 1K CK/14 CK + 4.1 ms + /// 0x15: Ext. Low-Freq. Crystal; Start-up time PWRDWN/RESET: 32K CK/14 CK + 4.1 ms + /// 0x16: Ext. Full-swing Crystal; Start-up time PWRDWN/RESET: 258 CK/14 CK + 65 ms + /// 0x17: Ext. Full-swing Crystal; Start-up time PWRDWN/RESET: 16K CK/14 CK + 0 ms + /// 0x18: Ext. Crystal Osc. 0.4-0.9 MHz; Start-up time PWRDWN/RESET: 258 CK/14 CK + 65 ms + /// 0x19: Ext. Crystal Osc. 0.4-0.9 MHz; Start-up time PWRDWN/RESET: 16K CK/14 CK + 0 ms + /// 0x1a: Ext. Crystal Osc. 0.9-3.0 MHz; Start-up time PWRDWN/RESET: 258 CK/14 CK + 65 ms + /// 0x1b: Ext. Crystal Osc. 0.9-3.0 MHz; Start-up time PWRDWN/RESET: 16K CK/14 CK + 0 ms + /// 0x1c: Ext. Crystal Osc. 3.0-8.0 MHz; Start-up time PWRDWN/RESET: 258 CK/14 CK + 65 ms + /// 0x1d: Ext. Crystal Osc. 3.0-8.0 MHz; Start-up time PWRDWN/RESET: 16K CK/14 CK + 0 ms + /// 0x1e: Ext. Crystal Osc. 8.0- MHz; Start-up time PWRDWN/RESET: 258 CK/14 CK + 65 ms + /// 0x1f: Ext. Crystal Osc. 8.0- MHz; Start-up time PWRDWN/RESET: 16K CK/14 CK + 0 ms + /// 0x20: Ext. Clock; Start-up time PWRDWN/RESET: 6 CK/14 CK + 65 ms + /// 0x22: Int. RC Osc. 8 MHz; Start-up time PWRDWN/RESET: 6 CK/14 CK + 65 ms + /// 0x23: Int. RC Osc. 128kHz; Start-up time PWRDWN/RESET: 6 CK/14 CK + 65 ms + /// 0x24: Ext. Low-Freq. Crystal; Start-up time PWRDWN/RESET: 1K CK/14 CK + 65 ms + /// 0x25: Ext. Low-Freq. Crystal; Start-up time PWRDWN/RESET: 32K CK/14 CK + 65 ms + /// 0x26: Ext. Full-swing Crystal; Start-up time PWRDWN/RESET: 1K CK /14 CK + 0 ms + /// 0x27: Ext. Full-swing Crystal; Start-up time PWRDWN/RESET: 16K CK/14 CK + 4.1 ms + /// 0x28: Ext. Crystal Osc. 0.4-0.9 MHz; Start-up time PWRDWN/RESET: 1K CK /14 CK + 0 ms + /// 0x29: Ext. Crystal Osc. 0.4-0.9 MHz; Start-up time PWRDWN/RESET: 16K CK/14 CK + 4.1 ms + /// 0x2a: Ext. Crystal Osc. 0.9-3.0 MHz; Start-up time PWRDWN/RESET: 1K CK /14 CK + 0 ms + /// 0x2b: Ext. Crystal Osc. 0.9-3.0 MHz; Start-up time PWRDWN/RESET: 16K CK/14 CK + 4.1 ms + /// 0x2c: Ext. Crystal Osc. 3.0-8.0 MHz; Start-up time PWRDWN/RESET: 1K CK /14 CK + 0 ms + /// 0x2d: Ext. Crystal Osc. 3.0-8.0 MHz; Start-up time PWRDWN/RESET: 16K CK/14 CK + 4.1 ms + /// 0x2e: Ext. Crystal Osc. 8.0- MHz; Start-up time PWRDWN/RESET: 1K CK /14 CK + 0 ms + /// 0x2f: Ext. Crystal Osc. 8.0- MHz; Start-up time PWRDWN/RESET: 16K CK/14 CK + 4.1 ms + /// 0x36: Ext. Full-swing Crystal; Start-up time PWRDWN/RESET: 1K CK /14 CK + 4.1 ms + /// 0x37: Ext. Full-swing Crystal; Start-up time PWRDWN/RESET: 16K CK/14 CK + 65 ms + /// 0x38: Ext. Crystal Osc. 0.4-0.9 MHz; Start-up time PWRDWN/RESET: 1K CK /14 CK + 4.1 ms + /// 0x39: Ext. Crystal Osc. 0.4-0.9 MHz; Start-up time PWRDWN/RESET: 16K CK/14 CK + 65 ms + /// 0x3a: Ext. Crystal Osc. 0.9-3.0 MHz; Start-up time PWRDWN/RESET: 1K CK /14 CK + 4.1 ms + /// 0x3b: Ext. Crystal Osc. 0.9-3.0 MHz; Start-up time PWRDWN/RESET: 16K CK/14 CK + 65 ms + /// 0x3c: Ext. Crystal Osc. 3.0-8.0 MHz; Start-up time PWRDWN/RESET: 1K CK /14 CK + 4.1 ms + /// 0x3d: Ext. Crystal Osc. 3.0-8.0 MHz; Start-up time PWRDWN/RESET: 16K CK/14 CK + 65 ms + /// 0x3e: Ext. Crystal Osc. 8.0- MHz; Start-up time PWRDWN/RESET: 1K CK /14 CK + 4.1 ms + /// 0x3f: Ext. Crystal Osc. 8.0- MHz; Start-up time PWRDWN/RESET: 16K CK/14 CK + 65 ms + SUT_CKSEL: u6, + /// Clock output on PORTB0 + CKOUT: u1, + /// Divide clock by 8 internally + CKDIV8: u1, + }), 0x0); + }; + + /// Lockbits + pub const LOCKBIT = struct { + + /// address: 0x0 + pub const LOCKBIT = @intToPtr(*volatile Mmio(8, packed struct { + /// Memory Lock + /// + /// 0x0: Further programming and verification disabled + /// 0x2: Further programming disabled + /// 0x3: No memory lock features enabled + LB: u2, + /// Boot Loader Protection Mode + /// + /// 0x0: LPM and SPM prohibited in Application Section + /// 0x1: LPM prohibited in Application Section + /// 0x2: SPM prohibited in Application Section + /// 0x3: No lock on SPM and LPM in Application Section + BLB0: u2, + /// Boot Loader Protection Mode + /// + /// 0x0: LPM and SPM prohibited in Boot Section + /// 0x1: LPM prohibited in Boot Section + /// 0x2: SPM prohibited in Boot Section + /// 0x3: No lock on SPM and LPM in Boot Section + BLB1: u2, + padding0: u1, + padding1: u1, + }), 0x0); + }; + + /// USART + pub const USART0 = struct { + + /// address: 0xc6 + /// USART I/O Data Register + pub const UDR0 = @intToPtr(*volatile u8, 0xc6); + + /// address: 0xc0 + /// USART Control and Status Register A + pub const UCSR0A = @intToPtr(*volatile Mmio(8, packed struct { + /// Multi-processor Communication Mode + MPCM0: u1, + /// Double the USART transmission speed + U2X0: u1, + /// Parity Error + UPE0: u1, + /// Data overRun + DOR0: u1, + /// Framing Error + FE0: u1, + /// USART Data Register Empty + UDRE0: u1, + /// USART Transmitt Complete + TXC0: u1, + /// USART Receive Complete + RXC0: u1, + }), 0xc0); + + /// address: 0xc1 + /// USART Control and Status Register B + pub const UCSR0B = @intToPtr(*volatile Mmio(8, packed struct { + /// Transmit Data Bit 8 + TXB80: u1, + /// Receive Data Bit 8 + RXB80: u1, + /// Character Size - together with UCSZ0 in UCSR0C + UCSZ02: u1, + /// Transmitter Enable + TXEN0: u1, + /// Receiver Enable + RXEN0: u1, + /// USART Data register Empty Interrupt Enable + UDRIE0: u1, + /// TX Complete Interrupt Enable + TXCIE0: u1, + /// RX Complete Interrupt Enable + RXCIE0: u1, + }), 0xc1); + + /// address: 0xc2 + /// USART Control and Status Register C + pub const UCSR0C = @intToPtr(*volatile Mmio(8, packed struct { + /// Clock Polarity + UCPOL0: u1, + /// Character Size - together with UCSZ2 in UCSR0B + UCSZ0: u2, + /// Stop Bit Select + /// + /// 0x0: 1-bit + /// 0x1: 2-bit + USBS0: u1, + /// Parity Mode Bits + /// + /// 0x0: Disabled + /// 0x1: Reserved + /// 0x2: Enabled, Even Parity + /// 0x3: Enabled, Odd Parity + UPM0: u2, + /// USART Mode Select + /// + /// 0x0: Asynchronous USART + /// 0x1: Synchronous USART + /// 0x3: Master SPI + UMSEL0: u2, + }), 0xc2); + + /// address: 0xc4 + /// USART Baud Rate Register Bytes + pub const UBRR0 = @intToPtr(*volatile u12, 0xc4); + }; + + /// Two Wire Serial Interface + pub const TWI = struct { + + /// address: 0xbd + /// TWI (Slave) Address Mask Register + pub const TWAMR = @intToPtr(*volatile Mmio(8, packed struct { + reserved0: u1, + TWAM: u7, + }), 0xbd); + + /// address: 0xb8 + /// TWI Bit Rate register + pub const TWBR = @intToPtr(*volatile u8, 0xb8); + + /// address: 0xbc + /// TWI Control Register + pub const TWCR = @intToPtr(*volatile Mmio(8, packed struct { + /// TWI Interrupt Enable + TWIE: u1, + reserved0: u1, + /// TWI Enable Bit + TWEN: u1, + /// TWI Write Collition Flag + TWWC: u1, + /// TWI Stop Condition Bit + TWSTO: u1, + /// TWI Start Condition Bit + TWSTA: u1, + /// TWI Enable Acknowledge Bit + TWEA: u1, + /// TWI Interrupt Flag + TWINT: u1, + }), 0xbc); + + /// address: 0xb9 + /// TWI Status Register + pub const TWSR = @intToPtr(*volatile Mmio(8, packed struct { + /// TWI Prescaler + /// + /// 0x0: 1 + /// 0x1: 4 + /// 0x2: 16 + /// 0x3: 64 + TWPS: u2, + reserved0: u1, + /// TWI Status + TWS: u5, + }), 0xb9); + + /// address: 0xbb + /// TWI Data register + pub const TWDR = @intToPtr(*volatile u8, 0xbb); + + /// address: 0xba + /// TWI (Slave) Address register + pub const TWAR = @intToPtr(*volatile Mmio(8, packed struct { + /// TWI General Call Recognition Enable Bit + TWGCE: u1, + /// TWI (Slave) Address register Bits + TWA: u7, + }), 0xba); + }; + + /// Timer/Counter, 16-bit + pub const TC1 = struct { + + /// address: 0x6f + /// Timer/Counter Interrupt Mask Register + pub const TIMSK1 = @intToPtr(*volatile Mmio(8, packed struct { + /// Timer/Counter1 Overflow Interrupt Enable + TOIE1: u1, + /// Timer/Counter1 Output CompareA Match Interrupt Enable + OCIE1A: u1, + /// Timer/Counter1 Output CompareB Match Interrupt Enable + OCIE1B: u1, + reserved0: u1, + reserved1: u1, + /// Timer/Counter1 Input Capture Interrupt Enable + ICIE1: u1, + padding0: u1, + padding1: u1, + }), 0x6f); + + /// address: 0x36 + /// Timer/Counter Interrupt Flag register + pub const TIFR1 = @intToPtr(*volatile Mmio(8, packed struct { + /// Timer/Counter1 Overflow Flag + TOV1: u1, + /// Output Compare Flag 1A + OCF1A: u1, + /// Output Compare Flag 1B + OCF1B: u1, + reserved0: u1, + reserved1: u1, + /// Input Capture Flag 1 + ICF1: u1, + padding0: u1, + padding1: u1, + }), 0x36); + + /// address: 0x80 + /// Timer/Counter1 Control Register A + pub const TCCR1A = @intToPtr(*volatile Mmio(8, packed struct { + /// Waveform Generation Mode + WGM1: u2, + reserved0: u1, + reserved1: u1, + /// Compare Output Mode 1B, bits + COM1B: u2, + /// Compare Output Mode 1A, bits + COM1A: u2, + }), 0x80); + + /// address: 0x81 + /// Timer/Counter1 Control Register B + pub const TCCR1B = @intToPtr(*volatile Mmio(8, packed struct { + /// Prescaler source of Timer/Counter 1 + /// + /// 0x0: No Clock Source (Stopped) + /// 0x1: Running, No Prescaling + /// 0x2: Running, CLK/8 + /// 0x3: Running, CLK/64 + /// 0x4: Running, CLK/256 + /// 0x5: Running, CLK/1024 + /// 0x6: Running, ExtClk Tn Falling Edge + /// 0x7: Running, ExtClk Tn Rising Edge + CS1: u3, + /// Waveform Generation Mode + WGM1: u2, + reserved0: u1, + /// Input Capture 1 Edge Select + ICES1: u1, + /// Input Capture 1 Noise Canceler + ICNC1: u1, + }), 0x81); + + /// address: 0x82 + /// Timer/Counter1 Control Register C + pub const TCCR1C = @intToPtr(*volatile Mmio(8, packed struct { + reserved0: u1, + reserved1: u1, + reserved2: u1, + reserved3: u1, + reserved4: u1, + reserved5: u1, + FOC1B: u1, + FOC1A: u1, + }), 0x82); + + /// address: 0x84 + /// Timer/Counter1 Bytes + pub const TCNT1 = @intToPtr(*volatile u16, 0x84); + + /// address: 0x88 + /// Timer/Counter1 Output Compare Register Bytes + pub const OCR1A = @intToPtr(*volatile u16, 0x88); + + /// address: 0x8a + /// Timer/Counter1 Output Compare Register Bytes + pub const OCR1B = @intToPtr(*volatile u16, 0x8a); + + /// address: 0x86 + /// Timer/Counter1 Input Capture Register Bytes + pub const ICR1 = @intToPtr(*volatile u16, 0x86); + + /// address: 0x43 + /// General Timer/Counter Control Register + pub const GTCCR = @intToPtr(*volatile Mmio(8, packed struct { + /// Prescaler Reset Timer/Counter1 and Timer/Counter0 + PSRSYNC: u1, + reserved0: u1, + reserved1: u1, + reserved2: u1, + reserved3: u1, + reserved4: u1, + reserved5: u1, + /// Timer/Counter Synchronization Mode + TSM: u1, + }), 0x43); + }; + + /// Timer/Counter, 8-bit Async + pub const TC2 = struct { + + /// address: 0x70 + /// Timer/Counter Interrupt Mask register + pub const TIMSK2 = @intToPtr(*volatile Mmio(8, packed struct { + /// Timer/Counter2 Overflow Interrupt Enable + TOIE2: u1, + /// Timer/Counter2 Output Compare Match A Interrupt Enable + OCIE2A: u1, + /// Timer/Counter2 Output Compare Match B Interrupt Enable + OCIE2B: u1, + padding0: u1, + padding1: u1, + padding2: u1, + padding3: u1, + padding4: u1, + }), 0x70); + + /// address: 0x37 + /// Timer/Counter Interrupt Flag Register + pub const TIFR2 = @intToPtr(*volatile Mmio(8, packed struct { + /// Timer/Counter2 Overflow Flag + TOV2: u1, + /// Output Compare Flag 2A + OCF2A: u1, + /// Output Compare Flag 2B + OCF2B: u1, + padding0: u1, + padding1: u1, + padding2: u1, + padding3: u1, + padding4: u1, + }), 0x37); + + /// address: 0xb0 + /// Timer/Counter2 Control Register A + pub const TCCR2A = @intToPtr(*volatile Mmio(8, packed struct { + /// Waveform Genration Mode + WGM2: u2, + reserved0: u1, + reserved1: u1, + /// Compare Output Mode bits + COM2B: u2, + /// Compare Output Mode bits + COM2A: u2, + }), 0xb0); + + /// address: 0xb1 + /// Timer/Counter2 Control Register B + pub const TCCR2B = @intToPtr(*volatile Mmio(8, packed struct { + /// Clock Select bits + /// + /// 0x0: No Clock Source (Stopped) + /// 0x1: Running, No Prescaling + /// 0x2: Running, CLK/8 + /// 0x3: Running, CLK/32 + /// 0x4: Running, CLK/64 + /// 0x5: Running, CLK/128 + /// 0x6: Running, CLK/256 + /// 0x7: Running, CLK/1024 + CS2: u3, + /// Waveform Generation Mode + WGM22: u1, + reserved0: u1, + reserved1: u1, + /// Force Output Compare B + FOC2B: u1, + /// Force Output Compare A + FOC2A: u1, + }), 0xb1); + + /// address: 0xb2 + /// Timer/Counter2 + pub const TCNT2 = @intToPtr(*volatile u8, 0xb2); + + /// address: 0xb4 + /// Timer/Counter2 Output Compare Register B + pub const OCR2B = @intToPtr(*volatile u8, 0xb4); + + /// address: 0xb3 + /// Timer/Counter2 Output Compare Register A + pub const OCR2A = @intToPtr(*volatile u8, 0xb3); + + /// address: 0xb6 + /// Asynchronous Status Register + pub const ASSR = @intToPtr(*volatile Mmio(8, packed struct { + /// Timer/Counter Control Register2 Update Busy + TCR2BUB: u1, + /// Timer/Counter Control Register2 Update Busy + TCR2AUB: u1, + /// Output Compare Register 2 Update Busy + OCR2BUB: u1, + /// Output Compare Register2 Update Busy + OCR2AUB: u1, + /// Timer/Counter2 Update Busy + TCN2UB: u1, + /// Asynchronous Timer/Counter2 + AS2: u1, + /// Enable External Clock Input + EXCLK: u1, + padding0: u1, + }), 0xb6); + + /// address: 0x43 + /// General Timer Counter Control register + pub const GTCCR = @intToPtr(*volatile Mmio(8, packed struct { + reserved0: u1, + /// Prescaler Reset Timer/Counter2 + PSRASY: u1, + reserved1: u1, + reserved2: u1, + reserved3: u1, + reserved4: u1, + reserved5: u1, + /// Timer/Counter Synchronization Mode + TSM: u1, + }), 0x43); + }; + + /// Analog-to-Digital Converter + pub const ADC = struct { + + /// address: 0x7c + /// The ADC multiplexer Selection Register + pub const ADMUX = @intToPtr(*volatile Mmio(8, packed struct { + /// Analog Channel Selection Bits + /// + /// 0x0: ADC Single Ended Input pin 0 + /// 0x1: ADC Single Ended Input pin 1 + /// 0x2: ADC Single Ended Input pin 2 + /// 0x3: ADC Single Ended Input pin 3 + /// 0x4: ADC Single Ended Input pin 4 + /// 0x5: ADC Single Ended Input pin 5 + /// 0x6: ADC Single Ended Input pin 6 + /// 0x7: ADC Single Ended Input pin 7 + /// 0x8: Temperature sensor + /// 0xe: Internal Reference (VBG) + /// 0xf: 0V (GND) + MUX: u4, + reserved0: u1, + /// Left Adjust Result + ADLAR: u1, + /// Reference Selection Bits + /// + /// 0x0: AREF, Internal Vref turned off + /// 0x1: AVCC with external capacitor at AREF pin + /// 0x2: Reserved + /// 0x3: Internal 1.1V Voltage Reference with external capacitor at AREF pin + REFS: u2, + }), 0x7c); + + /// address: 0x78 + /// ADC Data Register Bytes + pub const ADC = @intToPtr(*volatile u16, 0x78); + + /// address: 0x7a + /// The ADC Control and Status register A + pub const ADCSRA = @intToPtr(*volatile Mmio(8, packed struct { + /// ADC Prescaler Select Bits + /// + /// 0x0: 2 + /// 0x1: 2 + /// 0x2: 4 + /// 0x3: 8 + /// 0x4: 16 + /// 0x5: 32 + /// 0x6: 64 + /// 0x7: 128 + ADPS: u3, + /// ADC Interrupt Enable + ADIE: u1, + /// ADC Interrupt Flag + ADIF: u1, + /// ADC Auto Trigger Enable + ADATE: u1, + /// ADC Start Conversion + ADSC: u1, + /// ADC Enable + ADEN: u1, + }), 0x7a); + + /// address: 0x7b + /// The ADC Control and Status register B + pub const ADCSRB = @intToPtr(*volatile Mmio(8, packed struct { + /// ADC Auto Trigger Source bits + /// + /// 0x0: Free Running mode + /// 0x1: Analog Comparator + /// 0x2: External Interrupt Request 0 + /// 0x3: Timer/Counter0 Compare Match A + /// 0x4: Timer/Counter0 Overflow + /// 0x5: Timer/Counter1 Compare Match B + /// 0x6: Timer/Counter1 Overflow + /// 0x7: Timer/Counter1 Capture Event + ADTS: u3, + reserved0: u1, + reserved1: u1, + reserved2: u1, + ACME: u1, + padding0: u1, + }), 0x7b); + + /// address: 0x7e + /// Digital Input Disable Register + pub const DIDR0 = @intToPtr(*volatile Mmio(8, packed struct { + ADC0D: u1, + ADC1D: u1, + ADC2D: u1, + ADC3D: u1, + ADC4D: u1, + ADC5D: u1, + padding0: u1, + padding1: u1, + }), 0x7e); + }; + + /// Analog Comparator + pub const AC = struct { + + /// address: 0x50 + /// Analog Comparator Control And Status Register + pub const ACSR = @intToPtr(*volatile Mmio(8, packed struct { + /// Analog Comparator Interrupt Mode Select bits + /// + /// 0x0: Interrupt on Toggle + /// 0x1: Reserved + /// 0x2: Interrupt on Falling Edge + /// 0x3: Interrupt on Rising Edge + ACIS: u2, + /// Analog Comparator Input Capture Enable + ACIC: u1, + /// Analog Comparator Interrupt Enable + ACIE: u1, + /// Analog Comparator Interrupt Flag + ACI: u1, + /// Analog Compare Output + ACO: u1, + /// Analog Comparator Bandgap Select + ACBG: u1, + /// Analog Comparator Disable + ACD: u1, + }), 0x50); + + /// address: 0x7f + /// Digital Input Disable Register 1 + pub const DIDR1 = @intToPtr(*volatile Mmio(8, packed struct { + /// AIN0 Digital Input Disable + AIN0D: u1, + /// AIN1 Digital Input Disable + AIN1D: u1, + padding0: u1, + padding1: u1, + padding2: u1, + padding3: u1, + padding4: u1, + padding5: u1, + }), 0x7f); + }; + + /// I/O Port + pub const PORTB = struct { + + /// address: 0x25 + /// Port B Data Register + pub const PORTB = @intToPtr(*volatile u8, 0x25); + + /// address: 0x24 + /// Port B Data Direction Register + pub const DDRB = @intToPtr(*volatile u8, 0x24); + + /// address: 0x23 + /// Port B Input Pins + pub const PINB = @intToPtr(*volatile u8, 0x23); + }; + + /// I/O Port + pub const PORTC = struct { + + /// address: 0x28 + /// Port C Data Register + pub const PORTC = @intToPtr(*volatile u7, 0x28); + + /// address: 0x27 + /// Port C Data Direction Register + pub const DDRC = @intToPtr(*volatile u7, 0x27); + + /// address: 0x26 + /// Port C Input Pins + pub const PINC = @intToPtr(*volatile u7, 0x26); + }; + + /// I/O Port + pub const PORTD = struct { + + /// address: 0x2b + /// Port D Data Register + pub const PORTD = @intToPtr(*volatile u8, 0x2b); + + /// address: 0x2a + /// Port D Data Direction Register + pub const DDRD = @intToPtr(*volatile u8, 0x2a); + + /// address: 0x29 + /// Port D Input Pins + pub const PIND = @intToPtr(*volatile u8, 0x29); + }; + + /// Timer/Counter, 8-bit + pub const TC0 = struct { + + /// address: 0x48 + /// Timer/Counter0 Output Compare Register + pub const OCR0B = @intToPtr(*volatile u8, 0x48); + + /// address: 0x47 + /// Timer/Counter0 Output Compare Register + pub const OCR0A = @intToPtr(*volatile u8, 0x47); + + /// address: 0x46 + /// Timer/Counter0 + pub const TCNT0 = @intToPtr(*volatile u8, 0x46); + + /// address: 0x45 + /// Timer/Counter Control Register B + pub const TCCR0B = @intToPtr(*volatile Mmio(8, packed struct { + /// Clock Select + /// + /// 0x0: No Clock Source (Stopped) + /// 0x1: Running, No Prescaling + /// 0x2: Running, CLK/8 + /// 0x3: Running, CLK/64 + /// 0x4: Running, CLK/256 + /// 0x5: Running, CLK/1024 + /// 0x6: Running, ExtClk Tn Falling Edge + /// 0x7: Running, ExtClk Tn Rising Edge + CS0: u3, + WGM02: u1, + reserved0: u1, + reserved1: u1, + /// Force Output Compare B + FOC0B: u1, + /// Force Output Compare A + FOC0A: u1, + }), 0x45); + + /// address: 0x44 + /// Timer/Counter Control Register A + pub const TCCR0A = @intToPtr(*volatile Mmio(8, packed struct { + /// Waveform Generation Mode + WGM0: u2, + reserved0: u1, + reserved1: u1, + /// Compare Output Mode, Fast PWm + COM0B: u2, + /// Compare Output Mode, Phase Correct PWM Mode + COM0A: u2, + }), 0x44); + + /// address: 0x6e + /// Timer/Counter0 Interrupt Mask Register + pub const TIMSK0 = @intToPtr(*volatile Mmio(8, packed struct { + /// Timer/Counter0 Overflow Interrupt Enable + TOIE0: u1, + /// Timer/Counter0 Output Compare Match A Interrupt Enable + OCIE0A: u1, + /// Timer/Counter0 Output Compare Match B Interrupt Enable + OCIE0B: u1, + padding0: u1, + padding1: u1, + padding2: u1, + padding3: u1, + padding4: u1, + }), 0x6e); + + /// address: 0x35 + /// Timer/Counter0 Interrupt Flag register + pub const TIFR0 = @intToPtr(*volatile Mmio(8, packed struct { + /// Timer/Counter0 Overflow Flag + TOV0: u1, + /// Timer/Counter0 Output Compare Flag 0A + OCF0A: u1, + /// Timer/Counter0 Output Compare Flag 0B + OCF0B: u1, + padding0: u1, + padding1: u1, + padding2: u1, + padding3: u1, + padding4: u1, + }), 0x35); + + /// address: 0x43 + /// General Timer/Counter Control Register + pub const GTCCR = @intToPtr(*volatile Mmio(8, packed struct { + /// Prescaler Reset Timer/Counter1 and Timer/Counter0 + PSRSYNC: u1, + reserved0: u1, + reserved1: u1, + reserved2: u1, + reserved3: u1, + reserved4: u1, + reserved5: u1, + /// Timer/Counter Synchronization Mode + TSM: u1, + }), 0x43); + }; + + /// External Interrupts + pub const EXINT = struct { + + /// address: 0x69 + /// External Interrupt Control Register + pub const EICRA = @intToPtr(*volatile Mmio(8, packed struct { + /// External Interrupt Sense Control 0 Bits + /// + /// 0x0: Low Level of INTX + /// 0x1: Any Logical Change of INTX + /// 0x2: Falling Edge of INTX + /// 0x3: Rising Edge of INTX + ISC0: u2, + /// External Interrupt Sense Control 1 Bits + /// + /// 0x0: Low Level of INTX + /// 0x1: Any Logical Change of INTX + /// 0x2: Falling Edge of INTX + /// 0x3: Rising Edge of INTX + ISC1: u2, + padding0: u1, + padding1: u1, + padding2: u1, + padding3: u1, + }), 0x69); + + /// address: 0x3d + /// External Interrupt Mask Register + pub const EIMSK = @intToPtr(*volatile Mmio(8, packed struct { + /// External Interrupt Request 1 Enable + INT: u2, + padding0: u1, + padding1: u1, + padding2: u1, + padding3: u1, + padding4: u1, + padding5: u1, + }), 0x3d); + + /// address: 0x3c + /// External Interrupt Flag Register + pub const EIFR = @intToPtr(*volatile Mmio(8, packed struct { + /// External Interrupt Flags + INTF: u2, + padding0: u1, + padding1: u1, + padding2: u1, + padding3: u1, + padding4: u1, + padding5: u1, + }), 0x3c); + + /// address: 0x68 + /// Pin Change Interrupt Control Register + pub const PCICR = @intToPtr(*volatile Mmio(8, packed struct { + /// Pin Change Interrupt Enables + PCIE: u3, + padding0: u1, + padding1: u1, + padding2: u1, + padding3: u1, + padding4: u1, + }), 0x68); + + /// address: 0x6d + /// Pin Change Mask Register 2 + pub const PCMSK2 = @intToPtr(*volatile Mmio(8, packed struct { + /// Pin Change Enable Masks + PCINT: u8, + }), 0x6d); + + /// address: 0x6c + /// Pin Change Mask Register 1 + pub const PCMSK1 = @intToPtr(*volatile Mmio(8, packed struct { + /// Pin Change Enable Masks + PCINT: u7, + padding0: u1, + }), 0x6c); + + /// address: 0x6b + /// Pin Change Mask Register 0 + pub const PCMSK0 = @intToPtr(*volatile Mmio(8, packed struct { + /// Pin Change Enable Masks + PCINT: u8, + }), 0x6b); + + /// address: 0x3b + /// Pin Change Interrupt Flag Register + pub const PCIFR = @intToPtr(*volatile Mmio(8, packed struct { + /// Pin Change Interrupt Flags + PCIF: u3, + padding0: u1, + padding1: u1, + padding2: u1, + padding3: u1, + padding4: u1, + }), 0x3b); + }; + + /// Serial Peripheral Interface + pub const SPI = struct { + + /// address: 0x4e + /// SPI Data Register + pub const SPDR = @intToPtr(*volatile u8, 0x4e); + + /// address: 0x4d + /// SPI Status Register + pub const SPSR = @intToPtr(*volatile Mmio(8, packed struct { + /// Double SPI Speed Bit + SPI2X: u1, + reserved0: u1, + reserved1: u1, + reserved2: u1, + reserved3: u1, + reserved4: u1, + /// Write Collision Flag + WCOL: u1, + /// SPI Interrupt Flag + SPIF: u1, + }), 0x4d); + + /// address: 0x4c + /// SPI Control Register + pub const SPCR = @intToPtr(*volatile Mmio(8, packed struct { + /// SPI Clock Rate Selects + /// + /// 0x0: fosc/2 or fosc/4 + /// 0x1: fosc/8 or fosc/16 + /// 0x2: fosc/32 or fosc/64 + /// 0x3: fosc/64 or fosc/128 + SPR: u2, + /// Clock Phase + CPHA: u1, + /// Clock polarity + CPOL: u1, + /// Master/Slave Select + MSTR: u1, + /// Data Order + DORD: u1, + /// SPI Enable + SPE: u1, + /// SPI Interrupt Enable + SPIE: u1, + }), 0x4c); + }; + + /// Watchdog Timer + pub const WDT = struct { + + /// address: 0x60 + /// Watchdog Timer Control Register + pub const WDTCSR = @intToPtr(*volatile Mmio(8, packed struct { + reserved0: u1, + reserved1: u1, + reserved2: u1, + /// Watch Dog Enable + WDE: u1, + /// Watchdog Change Enable + WDCE: u1, + reserved3: u1, + /// Watchdog Timeout Interrupt Enable + WDIE: u1, + /// Watchdog Timeout Interrupt Flag + WDIF: u1, + }), 0x60); + }; + + /// CPU Registers + pub const CPU = struct { + + /// address: 0x64 + /// Power Reduction Register + pub const PRR = @intToPtr(*volatile Mmio(8, packed struct { + /// Power Reduction ADC + PRADC: u1, + /// Power Reduction USART + PRUSART0: u1, + /// Power Reduction Serial Peripheral Interface + PRSPI: u1, + /// Power Reduction Timer/Counter1 + PRTIM1: u1, + reserved0: u1, + /// Power Reduction Timer/Counter0 + PRTIM0: u1, + /// Power Reduction Timer/Counter2 + PRTIM2: u1, + /// Power Reduction TWI + PRTWI: u1, + }), 0x64); + + /// address: 0x66 + /// Oscillator Calibration Value + pub const OSCCAL = @intToPtr(*volatile u8, 0x66); + + /// address: 0x61 + /// Clock Prescale Register + pub const CLKPR = @intToPtr(*volatile Mmio(8, packed struct { + /// Clock Prescaler Select Bits + /// + /// 0x0: 1 + /// 0x1: 2 + /// 0x2: 4 + /// 0x3: 8 + /// 0x4: 16 + /// 0x5: 32 + /// 0x6: 64 + /// 0x7: 128 + /// 0x8: 256 + CLKPS: u4, + reserved0: u1, + reserved1: u1, + reserved2: u1, + /// Clock Prescaler Change Enable + CLKPCE: u1, + }), 0x61); + + /// address: 0x5f + /// Status Register + pub const SREG = @intToPtr(*volatile Mmio(8, packed struct { + /// Carry Flag + C: u1, + /// Zero Flag + Z: u1, + /// Negative Flag + N: u1, + /// Two's Complement Overflow Flag + V: u1, + /// Sign Bit + S: u1, + /// Half Carry Flag + H: u1, + /// Bit Copy Storage + T: u1, + /// Global Interrupt Enable + I: u1, + }), 0x5f); + + /// address: 0x5d + /// Stack Pointer + pub const SP = @intToPtr(*volatile u12, 0x5d); + + /// address: 0x57 + /// Store Program Memory Control and Status Register + pub const SPMCSR = @intToPtr(*volatile Mmio(8, packed struct { + /// Store Program Memory + SPMEN: u1, + /// Page Erase + PGERS: u1, + /// Page Write + PGWRT: u1, + /// Boot Lock Bit Set + BLBSET: u1, + /// Read-While-Write section read enable + RWWSRE: u1, + /// Signature Row Read + SIGRD: u1, + /// Read-While-Write Section Busy + RWWSB: u1, + /// SPM Interrupt Enable + SPMIE: u1, + }), 0x57); + + /// address: 0x55 + /// MCU Control Register + pub const MCUCR = @intToPtr(*volatile Mmio(8, packed struct { + IVCE: u1, + IVSEL: u1, + reserved0: u1, + reserved1: u1, + PUD: u1, + /// BOD Sleep Enable + BODSE: u1, + /// BOD Sleep + BODS: u1, + padding0: u1, + }), 0x55); + + /// address: 0x54 + /// MCU Status Register + pub const MCUSR = @intToPtr(*volatile Mmio(8, packed struct { + /// Power-on reset flag + PORF: u1, + /// External Reset Flag + EXTRF: u1, + /// Brown-out Reset Flag + BORF: u1, + /// Watchdog Reset Flag + WDRF: u1, + padding0: u1, + padding1: u1, + padding2: u1, + padding3: u1, + }), 0x54); + + /// address: 0x53 + /// Sleep Mode Control Register + pub const SMCR = @intToPtr(*volatile Mmio(8, packed struct { + /// Sleep Enable + SE: u1, + /// Sleep Mode Select Bits + /// + /// 0x0: Idle + /// 0x1: ADC Noise Reduction (If Available) + /// 0x2: Power Down + /// 0x3: Power Save + /// 0x4: Reserved + /// 0x5: Reserved + /// 0x6: Standby + /// 0x7: Extended Standby + SM: u3, + padding0: u1, + padding1: u1, + padding2: u1, + padding3: u1, + }), 0x53); + + /// address: 0x4b + /// General Purpose I/O Register 2 + pub const GPIOR2 = @intToPtr(*volatile u8, 0x4b); + + /// address: 0x4a + /// General Purpose I/O Register 1 + pub const GPIOR1 = @intToPtr(*volatile u8, 0x4a); + + /// address: 0x3e + /// General Purpose I/O Register 0 + pub const GPIOR0 = @intToPtr(*volatile u8, 0x3e); + }; + + /// EEPROM + pub const EEPROM = struct { + + /// address: 0x41 + /// EEPROM Address Register Bytes + pub const EEAR = @intToPtr(*volatile u10, 0x41); + + /// address: 0x40 + /// EEPROM Data Register + pub const EEDR = @intToPtr(*volatile u8, 0x40); + + /// address: 0x3f + /// EEPROM Control Register + pub const EECR = @intToPtr(*volatile Mmio(8, packed struct { + /// EEPROM Read Enable + EERE: u1, + /// EEPROM Write Enable + EEPE: u1, + /// EEPROM Master Write Enable + EEMPE: u1, + /// EEPROM Ready Interrupt Enable + EERIE: u1, + /// EEPROM Programming Mode Bits + /// + /// 0x0: Erase and Write in one operation + /// 0x1: Erase Only + /// 0x2: Write Only + EEPM: u2, + padding0: u1, + padding1: u1, + }), 0x3f); + }; +}; + +const std = @import("std"); + +pub fn mmio(addr: usize, comptime size: u8, comptime PackedT: type) *volatile Mmio(size, PackedT) { + return @intToPtr(*volatile Mmio(size, PackedT), addr); +} + +pub fn Mmio(comptime size: u8, comptime PackedT: type) type { + if ((size % 8) != 0) + @compileError("size must be divisible by 8!"); + + if (!std.math.isPowerOfTwo(size / 8)) + @compileError("size must encode a power of two number of bytes!"); + + const IntT = std.meta.Int(.unsigned, size); + + if (@sizeOf(PackedT) != (size / 8)) + @compileError(std.fmt.comptimePrint("IntT and PackedT must have the same size!, they are {} and {} bytes respectively", .{ size / 8, @sizeOf(PackedT) })); + + return extern struct { + const Self = @This(); + + raw: IntT, + + pub const underlying_type = PackedT; + + pub inline fn read(addr: *volatile Self) PackedT { + return @bitCast(PackedT, addr.raw); + } + + pub inline fn write(addr: *volatile Self, val: PackedT) void { + // This is a workaround for a compiler bug related to miscompilation + // If the tmp var is not used, result location will fuck things up + var tmp = @bitCast(IntT, val); + addr.raw = tmp; + } + + pub inline fn modify(addr: *volatile Self, fields: anytype) void { + var val = read(addr); + inline for (@typeInfo(@TypeOf(fields)).Struct.fields) |field| { + @field(val, field.name) = @field(fields, field.name); + } + write(addr, val); + } + + pub inline fn toggle(addr: *volatile Self, fields: anytype) void { + var val = read(addr); + inline for (@typeInfo(@TypeOf(fields)).Struct.fields) |field| { + @field(val, @tagName(field.default_value.?)) = !@field(val, @tagName(field.default_value.?)); + } + write(addr, val); + } + }; +} + +pub fn MmioInt(comptime size: u8, comptime T: type) type { + return extern struct { + const Self = @This(); + + raw: std.meta.Int(.unsigned, size), + + pub inline fn read(addr: *volatile Self) T { + return @truncate(T, addr.raw); + } + + pub inline fn modify(addr: *volatile Self, val: T) void { + const Int = std.meta.Int(.unsigned, size); + const mask = ~@as(Int, (1 << @bitSizeOf(T)) - 1); + + var tmp = addr.raw; + addr.raw = (tmp & mask) | val; + } + }; +} + +pub fn mmioInt(addr: usize, comptime size: usize, comptime T: type) *volatile MmioInt(size, T) { + return @intToPtr(*volatile MmioInt(size, T), addr); +} + +const InterruptVector = extern union { + C: fn () callconv(.C) void, + Naked: fn () callconv(.Naked) void, + // Interrupt is not supported on arm +}; + +const unhandled = InterruptVector{ + .C = struct { + fn tmp() callconv(.C) noreturn { + @panic("unhandled interrupt"); + } + }.tmp, +}; diff --git a/src/modules/cpus/avr/avr5.zig b/src/modules/cpus/avr/avr5.zig index d53fd3a..ca72dcd 100644 --- a/src/modules/cpus/avr/avr5.zig +++ b/src/modules/cpus/avr/avr5.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const microzig = @import("microzig"); pub inline fn sei() void { asm volatile ("sei"); @@ -24,46 +25,77 @@ pub inline fn cbi(comptime reg: u5, comptime bit: u3) void { ); } -pub const startup_logic = struct { - comptime { - asm ( - \\.section microzig_flash_start - \\ jmp _start - \\ jmp _unhandled_vector - \\ jmp _unhandled_vector - \\ jmp _unhandled_vector - \\ jmp _unhandled_vector - \\ jmp _unhandled_vector - \\ jmp _unhandled_vector - \\ jmp _unhandled_vector - \\ jmp _unhandled_vector - \\ jmp _unhandled_vector - \\ jmp _unhandled_vector - \\ jmp _unhandled_vector - \\ jmp _unhandled_vector - \\ jmp _unhandled_vector - \\ jmp _unhandled_vector - \\ jmp _unhandled_vector - \\ jmp _unhandled_vector - \\ jmp _unhandled_vector - \\ jmp _unhandled_vector - \\ jmp _unhandled_vector - \\ jmp _unhandled_vector - \\ jmp _unhandled_vector - \\ jmp _unhandled_vector - \\ jmp _unhandled_vector - \\ jmp _unhandled_vector - \\ jmp _unhandled_vector - ); +pub const vector_table = blk: { + std.debug.assert(std.mem.eql(u8, "RESET", std.meta.fields(microzig.chip.VectorTable)[0].name)); + var asm_str: []const u8 = "jmp microzig_start\n"; + + const has_interrupts = @hasDecl(microzig.app, "interrupts"); + if (has_interrupts) { + if (@hasDecl(microzig.app.interrupts, "RESET")) + @compileError("Not allowed to overload the reset vector"); + + inline for (std.meta.declarations(microzig.app.interrupts)) |decl| { + if (!@hasField(microzig.chip.VectorTable, decl.name)) { + var msg: []const u8 = "There is no such interrupt as '" ++ decl.name ++ "'. ISRs the 'interrupts' namespace must be one of:\n"; + inline for (std.meta.fields(microzig.chip.VectorTable)) |field| { + if (!std.mem.eql(u8, "RESET", field.name)) { + msg = msg ++ " " ++ field.name ++ "\n"; + } + } + + @compileError(msg); + } + } + } + + inline for (std.meta.fields(microzig.chip.VectorTable)[1..]) |field| { + const new_insn = if (has_interrupts) overload: { + if (@hasDecl(microzig.app.interrupts, field.name)) { + const handler = @field(microzig.app.interrupts, field.name); + const calling_convention = switch (@typeInfo(@TypeOf(@field(microzig.app.interrupts, field.name)))) { + .Fn => |info| info.calling_convention, + else => @compileError("Declarations in 'interrupts' namespace must all be functions. '" ++ field.name ++ "' is not a function"), + }; + + const exported_fn = switch (calling_convention) { + .Unspecified => struct { + fn wrapper() callconv(.C) void { + if (calling_convention == .Unspecified) // TODO: workaround for some weird stage1 bug + @call(.{ .modifier = .always_inline }, handler, .{}); + } + }.wrapper, + else => @compileError("Just leave interrupt handlers with an unspecified calling convention"), + }; + + const exported_name = "microzig_isr_" ++ field.name; + const options = .{ .name = exported_name, .linkage = .Strong }; + @export(exported_fn, options); + break :overload "jmp " ++ exported_name; + } else { + break :overload "jmp microzig_unhandled_vector"; + } + } else "jmp microzig_unhandled_vector"; + + asm_str = asm_str ++ new_insn ++ "\n"; } - export fn _unhandled_vector() callconv(.Naked) noreturn { + const T = struct { + fn _start() callconv(.Naked) void { + asm volatile (asm_str); + } + }; + + break :blk T._start; +}; + +pub const startup_logic = struct { + export fn microzig_unhandled_vector() callconv(.Naked) noreturn { @panic("Unhandled interrupt"); } extern fn microzig_main() noreturn; - export fn _start() callconv(.Naked) noreturn { + export fn microzig_start() callconv(.Naked) noreturn { // At startup the stack pointer is at the end of RAM // so, no need to set it manually! diff --git a/tests/interrupt.zig b/tests/interrupt.zig index f16fdd8..601d7fb 100644 --- a/tests/interrupt.zig +++ b/tests/interrupt.zig @@ -1,4 +1,5 @@ const micro = @import("microzig"); +const builtin = @import("builtin"); // this program will only work on arm microcontrollers, and it might not // actually run correctly at first, it's just a test for declaring interrupts @@ -6,14 +7,19 @@ const micro = @import("microzig"); pub const panic = micro.panic; -pub const interrupts = struct { - pub fn SysTick() void { - @panic("hit systick!"); - } +pub const interrupts = switch (builtin.cpu.arch) { + .avr => struct { + pub fn INT0() void { + @panic("hit PCINT0"); + } + }, + else => struct { + pub fn SysTick() void { + @panic("hit systick!"); + } + }, }; pub fn main() void { - while (true) { - micro.cpu.wfi(); - } + while (true) {} }