# HG changeset patch # User Paul Boddie # Date 1494454871 -7200 # Node ID 1d1a968f269a03b521c7395e61bacaabb4c38d78 # Parent 99c45884949c711b1ea7474a79dd0b22bd68e3f8 Added support for updating the line data address after every other transfer. diff -r 99c45884949c -r 1d1a968f269a vga.S --- a/vga.S Thu May 11 00:11:48 2017 +0200 +++ b/vga.S Thu May 11 00:21:11 2017 +0200 @@ -226,7 +226,7 @@ lw $v1, 0($v0) li $t8, (1 << 16) /* PMPIF */ and $v1, $v1, $t8 - beqz $v1, irq_exit + beqz $v1, irq_dma nop irq_clear_pmp: @@ -237,6 +237,53 @@ li $v1, (1 << 16) /* IFS1<16> = PMPIF = 0 */ sw $v1, CLR($v0) +irq_dma: + + /* Check for a DMA interrupt condition. */ + + la $v0, IFS1 + lw $v1, 0($v0) + li $t8, (1 << 28) /* DMA0IF */ + and $v1, $v1, $t8 + beqz $v1, irq_exit + nop + + /* Test the block transfer completion interrupt flag. */ + + la $v0, DCH0INT + lw $v1, 0($v0) + andi $v1, $v1, (1 << 3) /* CHBCIF */ + beqz $v1, irq_clear_dma + nop + + /* Clear the block transfer completion interrupt flag. */ + + li $v1, (1 << 3) /* CHBCIF = 0 */ + sw $v1, CLR($v0) + + /* + Update the line data address if the line counter (referring to the + next line) is even. + */ + + andi $t8, $s0, 1 + bnez $t8, irq_clear_dma + nop + + /* Reference the next line and update the DMA source address. */ + + addiu $s2, $s2, LINE_LIMIT + jal update_dma_address + nop + +irq_clear_dma: + + /* Clear the DMA interrupt condition. */ + + la $v0, IFS1 + li $v1, (1 << 28) /* IFS1<28> = DMA0IF = 0 */ + sw $v1, CLR($v0) + irq_exit: eret nop @@ -334,12 +381,20 @@ la $s1, visible_start - /* Enable OC2. */ + /* Enable OC2 for the next line. */ la $v0, OC2CON li $v1, (1 << 15) sw $v1, SET($v0) + /* Set the start address for line data. */ + + move $s2, $zero + move $t8, $ra + jal update_dma_address + nop + move $ra, $t8 + _vsync_active_ret: jr $ra nop @@ -370,7 +425,7 @@ la $s1, vbp_active - /* Disable OC2. */ + /* Disable OC2 for the next line. */ la $v0, OC2CON li $v1, (1 << 15) @@ -402,6 +457,24 @@ +/* Common routines. */ + +update_dma_address: + la $v0, DCH0CON + li $v1, 0b10000000 + sw $v1, CLR($v0) + + la $v0, DCH0SSA + sw $s2, 0($v0) + + la $v0, DCH0CON + sw $v1, SET($v0) + + jr $ra + nop + + + /* Initialisation routines. */ init_timer2: @@ -585,20 +658,21 @@ Direct Memory Access initialisation. Write 160 pixels to the PMP for the line data. This is initiated by an output -compare interrupt. +compare interrupt. Upon completion of the transfer, a DMA interrupt initiates +the address update routine, changing the source address of the DMA channel. */ init_dma: /* Disable DMA interrupts. */ la $v0, IEC1 - li $v1, (7 << 28) /* IEC1<30:28> = DMA2IE, DMA1IE, DMA0IE = 0 */ + li $v1, (1 << 28) /* IEC1<28> = DMA0IE = 0 */ sw $v1, CLR($v0) /* Clear DMA interrupt flags. */ la $v0, IFS1 - li $v1, (7 << 28) /* IFS1<30:28> = DMA2IF, DMA1IF, DMA0IF = 0 */ + li $v1, (1 << 28) /* IFS1<28> = DMA0IF = 0 */ sw $v1, CLR($v0) /* Enable DMA. */ @@ -681,8 +755,28 @@ subu $v1, $v1, $t8 sw $v1, 0($v0) + /* + Use the block transfer completion interrupt to indicate when the source + address can be updated. + */ + la $v0, DCH0INT - sw $zero, 0($v0) + li $v1, (1 << 19) /* CHBCIE = 1 */ + sw $v1, 0($v0) + + /* Enable interrupt for address updating. */ + + la $v0, IPC10 + li $v1, 0b11111 /* DMA0IP, DMA0IS = 0 */ + sw $v1, CLR($v0) + + la $v0, IPC10 + li $v1, 0b11111 /* DMA0IP = 7, DMA0IS = 3 */ + sw $v1, SET($v0) + + la $v0, IEC1 + li $v1, (1 << 28) /* IEC1<28> = DMA0IE = 1 */ + /* sw $v1, SET($v0) */ /* Enable channels. */