diff --git a/sw/kernel/devices/interrupt_controller.h b/sw/kernel/devices/interrupt_controller.h new file mode 100644 index 0000000..b016676 --- /dev/null +++ b/sw/kernel/devices/interrupt_controller.h @@ -0,0 +1,32 @@ +#ifndef _INTERRUPT_CONTROLLER_H +#define _INTERRUPT_CONTROLLER_H + +#include + +// These need to be copied in interrupt_controller.s + +#define IRQ_CMD_ADDR 0xeffc +#define IRQ_DAT_ADDR 0xeffd + +#define IRQ_CMD_MASK 0xe0 +#define IRQ_REG_MASK 0x1f + +#define IRQ_CMD_READIRQ 0x00 +#define IRQ_CMD_ENABLE 0x20 +#define IRQ_CMD_TYPE 0x40 +#define IRQ_CMD_EOI 0xff + +#define IRQ_EDGE 0 +#define IRQ_LEVEL 1 + + + +void init_interrupt_controller(); + +void enable_irq(uint8_t type, uint8_t irqnum); +void disable_irq(uint8_t irqnum); + +// This should accept irqnum later. +void send_eoi(); + +#endif \ No newline at end of file diff --git a/sw/kernel/devices/interrupt_controller.s b/sw/kernel/devices/interrupt_controller.s new file mode 100644 index 0000000..349edd2 --- /dev/null +++ b/sw/kernel/devices/interrupt_controller.s @@ -0,0 +1,136 @@ +.MACPACK generic + +.autoimport + +.importzp tmp1, tmp2 + +.export _init_interrupt_controller +.export _enable_irq +.export _disable_irq +.export _send_eoi + +IRQ_CMD_ADDR = $effc +IRQ_DAT_ADDR = $effd + +IRQ_CMD_MASK = $e0 +IRQ_REG_MASK = $1f +IRQ_CMD_READIRQ = $00 +IRQ_CMD_ENABLE = $20 +IRQ_CMD_TYPE = $40 +IRQ_CMD_EOI = $ff + +.code + +; void init_irq(); +; mask all IRQs, set all type to edge. +.proc _init_interrupt_controller + ldx #$20 ; enable + ldy #$ff + jsr cmd_all + ldx #$40 ; edge type + ldy #$00 + jsr cmd_all + rts + +cmd_all: ; Send the same value to all 32 bytes + txa + add #$20 + sta tmp1 +loop: + txa + sta IRQ_CMD_ADDR + tya + sta IRQ_DAT_ADDR + inx + cpx tmp1 + blt loop + rts +.endproc + + +; void enable_irq(uint8_t type, uint8_t irqnum); +; in A: +.proc _enable_irq + ; Decide which byte we need to modify by dividing by 32 (>> 5) + pha + lsr + lsr + lsr + lsr + lsr ; A is now bytesel + sta tmp2 ; tmp2 is now bytesel + add #IRQ_CMD_ENABLE + sta IRQ_CMD_ADDR + lda IRQ_DAT_ADDR + sta tmp1 + pla + and $07 ; A is now 0-7 + tax + inx ; X is now 1-8 + lda #$01 +L1: dex + beq L2 + asl + bra L1 +L2: pha ; Push bit mask to stack + ora tmp1 ; A is now 1 << (0-7) | enable + sta IRQ_DAT_ADDR + + + lda tmp2 + add #IRQ_CMD_TYPE + sta IRQ_CMD_ADDR + lda IRQ_DAT_ADDR + sta tmp1 + jsr popa ; A is now type + beq bit0 +bit1: ; set `bit` to 1 + pla + ora tmp1 + bra L3 +bit0: ; set `bit` to 0 + pla + eor #$ff + and tmp1 +L3: sta IRQ_DAT_ADDR + rts + +.endproc + +.proc _disable_irq + ; Decide which byte we need to modify by dividing by 32 (>> 5) + pha + lsr + lsr + lsr + lsr + lsr ; A is now bytesel + add #IRQ_CMD_ENABLE + sta IRQ_CMD_ADDR + lda IRQ_DAT_ADDR + sta tmp1 + pla + and $07 ; A is now 0-7 + tax + inx ; X is now 1-8 + lda #$01 +L1: dex + beq L2 + asl + bra L1 +L2: eor #$ff ; Invert to set enable to 0 + and tmp1 ; a is now ~(1 << (0-7)) & enable + sta IRQ_DAT_ADDR + rts +.endproc + +; This should accept irqnum later. +; void send_eoi(); +.proc _send_eoi + lda #IRQ_CMD_EOI + sta IRQ_CMD_ADDR + lda #$1 + sta IRQ_DAT_ADDR + rts +.endproc + diff --git a/sw/kernel/devices/rtc.h b/sw/kernel/devices/rtc.h new file mode 100644 index 0000000..913e7c6 --- /dev/null +++ b/sw/kernel/devices/rtc.h @@ -0,0 +1,16 @@ +#ifndef _RTC_H +#define _RTC_H + +#include + +#define RTC_CMD_ADDR 0xeffe +#define RTC_DAT_ADDR 0xefff + +/* initialize RTC with default values */ +void init_rtc(void); + +/* handle RTC interrupts */ +void handle_rtc(void); + + +#endif \ No newline at end of file diff --git a/sw/kernel/devices/rtc.s b/sw/kernel/devices/rtc.s new file mode 100644 index 0000000..864e223 --- /dev/null +++ b/sw/kernel/devices/rtc.s @@ -0,0 +1,78 @@ +.MACPACK generic + +.importzp tmp1 + +.export _init_rtc +.export _handle_rtc + +RTC_CMD = $effe +RTC_DAT = $efff + +RTC_THRESHOLD = $00 +RTC_INCREMENT = $10 +RTC_IRQ_THRESHOLD = $20 +RTC_OUTPUT = $30 +RTC_CONTROL = $30 + +; void init_rtc(void); +; Initialize rtc and generate 50ms interrupts +.proc _init_rtc + lda #RTC_INCREMENT+0 ; Set increment to 1 + sta RTC_CMD + lda #$01 + sta RTC_DAT + lda #RTC_INCREMENT+1 + sta RTC_CMD + lda #$00 + sta RTC_DAT + lda #RTC_INCREMENT+2 + sta RTC_CMD + lda #$00 + sta RTC_DAT + lda #RTC_INCREMENT+3 + sta RTC_CMD + lda #$00 + sta RTC_DAT + + lda #RTC_THRESHOLD+0 ; Set threshold to 4000 ($fa0) + sta RTC_CMD + lda #$a0 + sta RTC_DAT + lda #RTC_THRESHOLD+1 + sta RTC_CMD + lda #$0f + sta RTC_DAT + lda #RTC_THRESHOLD+2 + sta RTC_CMD + lda #$00 + sta RTC_DAT + lda #RTC_THRESHOLD+3 + sta RTC_CMD + lda #$00 + sta RTC_DAT + + lda #RTC_THRESHOLD+0 ; Set irq threshold to 50 ($32) + sta RTC_CMD + lda #$32 + sta RTC_DAT + lda #RTC_THRESHOLD+1 + sta RTC_CMD + lda #$00 + sta RTC_DAT + lda #RTC_THRESHOLD+2 + sta RTC_CMD + lda #$00 + sta RTC_DAT + lda #RTC_THRESHOLD+3 + sta RTC_CMD + lda #$00 + sta RTC_DAT + rts + +.endproc + + +.proc _handle_rtc + nop + rti +.endproc \ No newline at end of file diff --git a/sw/kernel/kernel.c b/sw/kernel/kernel.c index ef18f01..d69a0f1 100644 --- a/sw/kernel/kernel.c +++ b/sw/kernel/kernel.c @@ -1,25 +1,27 @@ #include - -char* longstring = \ -"This is a very long string that is meant to test the loader.\ - We can only load one cluster so far, which means 8 sectors of\ - 512bytes, or a total of 4k. If there was any more data than this,\ - then we would have to traverse the fat to find the next cluster number.\ - This may not be that difficult, but the file will need to be large\ - enough to actually stretch that far. The kernel will probably be\ - that big in the future, but for now when it doesnt really do anything\ - then it can't really be tested."; +#include "devices/interrupt_controller.h" +#include "devices/rtc.h" int main() { - char* string = "this is a shorter string"; - int val = 42; - cputs("Kernel\n"); - cprintf("Kernel printf\n"); - cprintf("Val: %d\n", val); - cprintf("%s", string); - cprintf("Here is a long string: %s\n", longstring); + cputs("Kernel\n"); + + // cputs("Init Paging") + // init_paging() + + // cputs("Initialize Interrupts"); + // init_interrupts(); + + cputs("Initialize Interrupt Controller"); + init_interrupt_controller(); + + cputs("Initialize RTC"); + init_rtc(); + + // cputs("Initialize Serial"); + // // init_serial(); + // enable_irq(2, IRQ_EDGE); while(1);