1.1 --- a/vga.S Thu May 11 00:11:48 2017 +0200
1.2 +++ b/vga.S Thu May 11 00:21:11 2017 +0200
1.3 @@ -226,7 +226,7 @@
1.4 lw $v1, 0($v0)
1.5 li $t8, (1 << 16) /* PMPIF */
1.6 and $v1, $v1, $t8
1.7 - beqz $v1, irq_exit
1.8 + beqz $v1, irq_dma
1.9 nop
1.10
1.11 irq_clear_pmp:
1.12 @@ -237,6 +237,53 @@
1.13 li $v1, (1 << 16) /* IFS1<16> = PMPIF = 0 */
1.14 sw $v1, CLR($v0)
1.15
1.16 +irq_dma:
1.17 +
1.18 + /* Check for a DMA interrupt condition. */
1.19 +
1.20 + la $v0, IFS1
1.21 + lw $v1, 0($v0)
1.22 + li $t8, (1 << 28) /* DMA0IF */
1.23 + and $v1, $v1, $t8
1.24 + beqz $v1, irq_exit
1.25 + nop
1.26 +
1.27 + /* Test the block transfer completion interrupt flag. */
1.28 +
1.29 + la $v0, DCH0INT
1.30 + lw $v1, 0($v0)
1.31 + andi $v1, $v1, (1 << 3) /* CHBCIF */
1.32 + beqz $v1, irq_clear_dma
1.33 + nop
1.34 +
1.35 + /* Clear the block transfer completion interrupt flag. */
1.36 +
1.37 + li $v1, (1 << 3) /* CHBCIF = 0 */
1.38 + sw $v1, CLR($v0)
1.39 +
1.40 + /*
1.41 + Update the line data address if the line counter (referring to the
1.42 + next line) is even.
1.43 + */
1.44 +
1.45 + andi $t8, $s0, 1
1.46 + bnez $t8, irq_clear_dma
1.47 + nop
1.48 +
1.49 + /* Reference the next line and update the DMA source address. */
1.50 +
1.51 + addiu $s2, $s2, LINE_LIMIT
1.52 + jal update_dma_address
1.53 + nop
1.54 +
1.55 +irq_clear_dma:
1.56 +
1.57 + /* Clear the DMA interrupt condition. */
1.58 +
1.59 + la $v0, IFS1
1.60 + li $v1, (1 << 28) /* IFS1<28> = DMA0IF = 0 */
1.61 + sw $v1, CLR($v0)
1.62 +
1.63 irq_exit:
1.64 eret
1.65 nop
1.66 @@ -334,12 +381,20 @@
1.67
1.68 la $s1, visible_start
1.69
1.70 - /* Enable OC2. */
1.71 + /* Enable OC2 for the next line. */
1.72
1.73 la $v0, OC2CON
1.74 li $v1, (1 << 15)
1.75 sw $v1, SET($v0)
1.76
1.77 + /* Set the start address for line data. */
1.78 +
1.79 + move $s2, $zero
1.80 + move $t8, $ra
1.81 + jal update_dma_address
1.82 + nop
1.83 + move $ra, $t8
1.84 +
1.85 _vsync_active_ret:
1.86 jr $ra
1.87 nop
1.88 @@ -370,7 +425,7 @@
1.89
1.90 la $s1, vbp_active
1.91
1.92 - /* Disable OC2. */
1.93 + /* Disable OC2 for the next line. */
1.94
1.95 la $v0, OC2CON
1.96 li $v1, (1 << 15)
1.97 @@ -402,6 +457,24 @@
1.98
1.99
1.100
1.101 +/* Common routines. */
1.102 +
1.103 +update_dma_address:
1.104 + la $v0, DCH0CON
1.105 + li $v1, 0b10000000
1.106 + sw $v1, CLR($v0)
1.107 +
1.108 + la $v0, DCH0SSA
1.109 + sw $s2, 0($v0)
1.110 +
1.111 + la $v0, DCH0CON
1.112 + sw $v1, SET($v0)
1.113 +
1.114 + jr $ra
1.115 + nop
1.116 +
1.117 +
1.118 +
1.119 /* Initialisation routines. */
1.120
1.121 init_timer2:
1.122 @@ -585,20 +658,21 @@
1.123 Direct Memory Access initialisation.
1.124
1.125 Write 160 pixels to the PMP for the line data. This is initiated by an output
1.126 -compare interrupt.
1.127 +compare interrupt. Upon completion of the transfer, a DMA interrupt initiates
1.128 +the address update routine, changing the source address of the DMA channel.
1.129 */
1.130
1.131 init_dma:
1.132 /* Disable DMA interrupts. */
1.133
1.134 la $v0, IEC1
1.135 - li $v1, (7 << 28) /* IEC1<30:28> = DMA2IE, DMA1IE, DMA0IE = 0 */
1.136 + li $v1, (1 << 28) /* IEC1<28> = DMA0IE = 0 */
1.137 sw $v1, CLR($v0)
1.138
1.139 /* Clear DMA interrupt flags. */
1.140
1.141 la $v0, IFS1
1.142 - li $v1, (7 << 28) /* IFS1<30:28> = DMA2IF, DMA1IF, DMA0IF = 0 */
1.143 + li $v1, (1 << 28) /* IFS1<28> = DMA0IF = 0 */
1.144 sw $v1, CLR($v0)
1.145
1.146 /* Enable DMA. */
1.147 @@ -681,8 +755,28 @@
1.148 subu $v1, $v1, $t8
1.149 sw $v1, 0($v0)
1.150
1.151 + /*
1.152 + Use the block transfer completion interrupt to indicate when the source
1.153 + address can be updated.
1.154 + */
1.155 +
1.156 la $v0, DCH0INT
1.157 - sw $zero, 0($v0)
1.158 + li $v1, (1 << 19) /* CHBCIE = 1 */
1.159 + sw $v1, 0($v0)
1.160 +
1.161 + /* Enable interrupt for address updating. */
1.162 +
1.163 + la $v0, IPC10
1.164 + li $v1, 0b11111 /* DMA0IP, DMA0IS = 0 */
1.165 + sw $v1, CLR($v0)
1.166 +
1.167 + la $v0, IPC10
1.168 + li $v1, 0b11111 /* DMA0IP = 7, DMA0IS = 3 */
1.169 + sw $v1, SET($v0)
1.170 +
1.171 + la $v0, IEC1
1.172 + li $v1, (1 << 28) /* IEC1<28> = DMA0IE = 1 */
1.173 + /* sw $v1, SET($v0) */
1.174
1.175 /* Enable channels. */
1.176