Pārlūkot izejas kodu

INTERRUPTS :D
HOLYSHIT THEY WORK

Streetwalrus Einstein 10 gadi atpakaļ
vecāks
revīzija
b4a480bb77
5 mainītis faili ar 87 papildinājumiem un 2 dzēšanām
  1. 1 0
      include/Graphics.h
  2. 13 0
      include/Interrupts.h
  3. 11 0
      src/Graphics.cpp
  4. 59 0
      src/Interrupts.cpp
  5. 3 2
      src/main.cpp

+ 1 - 0
include/Graphics.h

@@ -23,6 +23,7 @@ namespace WalrusRPG
 	 */
 
         void lcd_vsync();
+        void vsync_isr();
 
 
         /*

+ 13 - 0
include/Interrupts.h

@@ -0,0 +1,13 @@
+#ifndef INCLUDE_INTERRUPTS_H
+#define INCLUDE_INTERRUPTS_H
+
+namespace WalrusRPG
+{
+    namespace Interrupts
+    {
+        void init();
+        void off();
+        void __attribute__((interrupt("IRQ"))) isr();
+    }
+}
+#endif

+ 11 - 0
src/Graphics.cpp

@@ -10,6 +10,8 @@ volatile unsigned *lcd_ris = (unsigned *) (LCD_CONTROLLER + 0x20);
 volatile unsigned *lcd_icr = (unsigned *) (LCD_CONTROLLER + 0x28);
 volatile unsigned *lcd_control = (unsigned *) (LCD_CONTROLLER + 0x18);
 unsigned lcd_control_bkp;
+volatile unsigned *lcd_imsc = (unsigned *) (LCD_CONTROLLER + 0x1C);
+unsigned lcd_imsc_bkp;
 
 #define BUFFER_SIZE 320 * 240 * 2
 unsigned short *buffer_screen = NULL, *buffer_render = NULL, *buffer_ready = NULL, *buffer_os;
@@ -41,6 +43,8 @@ void GRAPHICS::buffer_allocate()
     lcd_control_bkp = *lcd_control;
     *lcd_control &= ~(0b11 << 12);
     *lcd_control |= 0b11 << 12;
+    lcd_imsc_bkp = *lcd_imsc;
+    *lcd_imsc = 1 << 3;
 }
 
 void GRAPHICS::buffer_free()
@@ -52,6 +56,7 @@ void GRAPHICS::buffer_free()
     *lcd_base = (unsigned) buffer_os;
 
     *lcd_control = lcd_control_bkp;
+    *lcd_imsc = lcd_imsc_bkp;
 }
 
 void GRAPHICS::buffer_swap_screen()
@@ -95,6 +100,12 @@ void GRAPHICS::lcd_vsync()
         ;
 }
 
+void GRAPHICS::vsync_isr()
+{
+    buffer_swap_screen();
+    *lcd_icr = 1 << 3;
+}
+
 
 /*
  * Drawing

+ 59 - 0
src/Interrupts.cpp

@@ -0,0 +1,59 @@
+#include "Interrupts.h"
+#include "Graphics.h"
+
+#define INTERRUPTS WalrusRPG::Interrupts
+
+#define INTERRUPT_CONTROLLER 0xDC000000
+volatile unsigned *irq_status = (unsigned *) (INTERRUPT_CONTROLLER + 0x0);
+volatile unsigned *interrupt_select = (unsigned *) (INTERRUPT_CONTROLLER + 0xC);
+unsigned interrupt_select_bkp;
+volatile unsigned *interrupt_enable = (unsigned *) (INTERRUPT_CONTROLLER + 0x10);
+volatile unsigned *interrupt_enable_clear = (unsigned *) (INTERRUPT_CONTROLLER + 0x14);
+unsigned interrupt_enable_bkp;
+
+volatile unsigned *interrupt_pointer = (unsigned *) 0x38;
+unsigned interrupt_pointer_bkp;
+
+// Interrupt source 21 is the LCD
+#define INTERRUPT_MASK (1 << 21)
+
+void INTERRUPTS::init()
+{
+    interrupt_select_bkp = *interrupt_select;
+    *interrupt_select = 0; // All IRQ for now
+
+    interrupt_enable_bkp = *interrupt_enable;
+    *interrupt_enable = INTERRUPT_MASK;
+    *interrupt_enable_clear = ~(INTERRUPT_MASK);
+
+    interrupt_pointer_bkp = *interrupt_pointer;
+    *interrupt_pointer = (unsigned) &isr;
+
+    // Enable IRQ in the CPU
+    asm("mrs r1, cpsr \n\t"
+            "bic r1, r1, #0x80 \n\t"
+            "msr cpsr, r1"
+            : : : "r1");
+}
+
+void INTERRUPTS::off()
+{
+    // Disable IRQ in the CPU
+    asm("mrs r1, cpsr \n\t"
+            "orr r1, r1, #0x80 \n\t"
+            "msr cpsr, r1"
+            : : : "r1");
+
+    *interrupt_select = interrupt_select_bkp;
+
+    *interrupt_enable = interrupt_enable_bkp;
+    *interrupt_enable_clear = ~(interrupt_enable_bkp);
+
+    *interrupt_pointer = interrupt_pointer_bkp;
+}
+
+void __attribute__((interrupt("IRQ"))) INTERRUPTS::isr()
+{
+    if (*irq_status & (1 << 21))
+        WalrusRPG::Graphics::vsync_isr();
+}

+ 3 - 2
src/main.cpp

@@ -10,6 +10,7 @@
 #include "misc.h"
 #include "sprites.h"
 #include "version.h"
+#include "Interrupts.h"
 
 using namespace WalrusRPG;
 using namespace WalrusRPG::Graphics;
@@ -65,9 +66,7 @@ void map_loop(unsigned x, unsigned y, Map &map)
             unsigned frame_stamp = timer_read(0);
             print_format(0, 240 - 8, "%u fps", 32768 / (last_frame - frame_stamp));
             last_frame = frame_stamp;
-            lcd_vsync();
             buffer_swap_render();
-            buffer_swap_screen();
         }
 
         // Frame limiting
@@ -84,6 +83,7 @@ int main(int argc, char *argv[])
 
     buffer_allocate();
     timer_init(0);
+    WalrusRPG::Interrupts::init();
 
     unsigned dungeonTest[] = {
         21, 21, 1, 1, 1, 1, 21, 22, 21, 22, 21, 22, 21, 21, 1, 22, 21, 1, 22, 22,
@@ -141,6 +141,7 @@ int main(int argc, char *argv[])
     map.anim.add_animation(22, {stripe22, true});
     map_loop(0, 0, map);
 
+    WalrusRPG::Interrupts::off();
     timer_restore(0);
     buffer_free();
     return 0;