paul_nicholls

Untitled

Feb 10th, 2026
212
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 3.82 KB | None | 0 0
  1. //------------------------------------------------------------------------
  2. //    This file is part of OmniPas.
  3. //
  4. //    You can find OmniPas here:
  5. //    https://bitbucket.org/paul_nicholls/omnipas/src/master/
  6. //
  7. //    this file was translated (and modified) from:
  8. //    https://github.com/SlithyMatt/zxs-assembly-tutorial/blob/main/Lesson12/irq.asm
  9. //
  10. //    OmniPas is free software: you can redistribute it and/or modify
  11. //    it under the terms of the GNU General Public License as published by
  12. //    the Free Software Foundation, either version 3 of the License, or
  13. //    (at your option) any later version.
  14. //
  15. //    OmniPas is distributed in the hope that it will be useful,
  16. //    but WITHOUT ANY WARRANTY// without even the implied warranty of
  17. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18. //    GNU General Public License for more details.
  19. //
  20. //    You should have received a copy of the GNU General Public License
  21. //    along with OmniPas.  If not, see <https://www.gnu.org/licenses/>.
  22. //------------------------------------------------------------------------
  23.  
  24. unit spectrum_irq;
  25.  
  26. type
  27.   TIRQ = record
  28.     framecounter : Word;
  29.     vbSync       : Byte;
  30.   end;
  31.  
  32. var
  33.   IRQ : TIRQ;
  34.  
  35. macro saveAllRegisters(); assembler;
  36. asm
  37.   // stash all registers to stack
  38.   push af
  39.   push bc
  40.   push de
  41.   push hl
  42.   ex af,af'                  // exchange AF and AF'
  43.   exx                        // exchange BE,DE,HL with BE',DE',HL'
  44.   push af
  45.   push bc
  46.   push de
  47.   push hl
  48.   push ix
  49.   push iy
  50. end;
  51.  
  52. macro restoreAllRegisters(); assembler;
  53. asm
  54.   // restore all registers from stack
  55.   pop iy
  56.   pop ix
  57.   pop hl
  58.   pop de
  59.   pop bc
  60.   pop af
  61.   ex af,af'                  // exchange AF and AF'
  62.   exx                        // exchange BE,DE,HL with BE',DE',HL'
  63.   pop hl
  64.   pop de
  65.   pop bc
  66.   pop af
  67. end;
  68.  
  69. macro exitIRQ(); assembler;
  70. asm
  71.   ei
  72. end;
  73.  
  74. procedure vbSyncIRQ; assembler; volatile;
  75. asm
  76.   :saveAllRegisters();
  77.  
  78.   // increment frame counter
  79.   ld hl,(IRQ.framecounter)
  80.   inc hl
  81.   ld (IRQ.framecounter),hl
  82.  
  83.   // set vertical blank sync
  84.   ld a,1
  85.   ld (IRQ.vbSync),a
  86.  
  87. USER_IRQ:
  88.   call $ffff
  89.  
  90.   :restoreAllRegisters();
  91.   :exitIRQ();
  92. end;
  93.  
  94. procedure waitFor_vblank(); assembler;
  95. asm
  96.   // wait for vbSync <> 0
  97. !:
  98.   ld a,(IRQ.vbSync)
  99.   cp 0
  100.   jp z,!-
  101.   // reset vbSync to 0
  102.   xor a
  103.   ld (IRQ.vbSync),a
  104. end;
  105.  
  106. procedure setupInterrupt(irqRoutineAddr : Word); assembler;
  107. const
  108.   IM2_TABLE  = $FE00; // 256 byte page (+ 1 byte) for IM2
  109.   IM2_VECTOR = $FDFD; // 3 bytes for JP routine under IM2 table
  110.  
  111. asm
  112.   // link user irq to our routine
  113.   ld hl,(irqRoutineAddr)
  114.   ld (vbSyncIRQ.USER_IRQ + 1),hl
  115.  
  116.   // zero counters
  117.   ld hl,0
  118.   ld (IRQ.framecounter),hl
  119.   xor a
  120.   ld (IRQ.vbSync),a
  121.  
  122.   // Setup Interrupt Mode 2
  123.   di                         // disable interrupts
  124.   ld de,IM2_TABLE            // de = beginning of 257 bytes to set to $FD
  125.   ld hl,IM2_VECTOR           // hl = vector location ($FDFD)
  126.   ld a,d                     //
  127.   ld i,a                     // i = custom IM2 table page
  128.   ld a,l                     // a = $FD
  129. fill_loop:
  130.   ld (de),a                  // set byte in IM2 table to $FD
  131.   inc e                      // de = next byte (unless e = 0)
  132.   jp nz,fill_loop            // loop until whole page is set to $FD (e = 0)
  133.   inc d                      // de = 257th byte of table
  134.   ld (de),a                  // set last byte to $FD
  135.   ld (hl),$C3                // place unconditional JP opcode at vector
  136.   inc l                      // hl = vector + 1
  137.   ld (hl),<vbSyncIRQ        // low byte of custom handler address
  138.   inc l                      // hl = vector + 2
  139.   ld (hl),>vbSyncIRQ        // high byte of custom handler address
  140.   im 2                       // set interrupt mode 2
  141.   ei                         // re-enable interrupts
  142. end;
  143.  
Advertisement
Add Comment
Please, Sign In to add comment