diff --git a/pat80-io-devices/composite-pal-adapter/software/avr-assembly/character_generator.asm b/pat80-io-devices/composite-pal-adapter/software/avr-assembly/character_generator.asm index 7e27df4..3df17ad 100644 --- a/pat80-io-devices/composite-pal-adapter/software/avr-assembly/character_generator.asm +++ b/pat80-io-devices/composite-pal-adapter/software/avr-assembly/character_generator.asm @@ -6,7 +6,7 @@ ; This module generates the character pixels using the font present in rom ; and adds it on the framebuffer in the position indicated by POS_COARSE (Y). -.equ LINE_COLUMNS = 52 ; number of columns (characters or chunks) per line +.equ LINE_COLUMNS = 46 ; number of columns (characters or chunks) per line ; Draws character in register A to the screen at current coords (Y) ; @param r16 (HIGH_ACCUM) ascii code to display @@ -75,11 +75,8 @@ cursor_pos_home: clr POS_ROWP clr POS_FINE ; Load framebuffer start position to Y - ; ldi YH, high(FRAMEBUFFER) - ; ldi YL, low(FRAMEBUFFER) - ; TODO: First 3 lines are not visible! Outside of screen! - ldi YH, high(0x780) - ldi YL, low(0x780) + ldi YH, high(FRAMEBUFFER) + ldi YL, low(FRAMEBUFFER) ret ; Updates framebuffer pointer (Y) to point to current text cursor position (POS_COLUMN, POS_ROWP) diff --git a/pat80-io-devices/composite-pal-adapter/software/avr-assembly/main.asm b/pat80-io-devices/composite-pal-adapter/software/avr-assembly/main.asm index ac3e2fa..076e924 100644 --- a/pat80-io-devices/composite-pal-adapter/software/avr-assembly/main.asm +++ b/pat80-io-devices/composite-pal-adapter/software/avr-assembly/main.asm @@ -1,7 +1,4 @@ ; VIDEO COMPOSITE PAL IO DEVICE -; Implemented following timings in http://blog.retroleum.co.uk/electronics-articles/pal-tv-timing-and-voltages/ -; Every line, for 52 times, it loads a byte from memory into PORTA register and then shifts the byte to the left to show another bit (do it 7 times) -; This also displays byte's MSB pixel "for free", as the video pin is PD7 (last bit of PORTA). ; ; INTERFACING WITH PAT80: ; Use PortB as data port. Before writing anything, issue a read (pin RW HIGH) and check the busy pin on the data port. @@ -55,7 +52,7 @@ ; memory .equ FRAMEBUFFER = 0x0100 -.equ FRAMEBUFFER_END = 0x3EC0 +.equ FRAMEBUFFER_END = 0x2AB0 ; start vector .org 0x0000 @@ -92,53 +89,17 @@ main: ; test draw character routine call cursor_pos_home - ldi r18, 0x21 - draw_chars: - mov HIGH_ACCUM, r18 - call draw_char - inc r18 - cpi r18, 0x7E - brne draw_chars - - ldi r18, 0x21 - draw_chars2: - mov HIGH_ACCUM, r18 - call draw_char - inc r18 - cpi r18, 0x7E - brne draw_chars2 - - ldi r18, 0x21 - draw_chars3: - mov HIGH_ACCUM, r18 - call draw_char - inc r18 - cpi r18, 0x7E - brne draw_chars3 - - ldi r18, 0x21 - draw_chars4: - mov HIGH_ACCUM, r18 - call draw_char - inc r18 - cpi r18, 0x7E - brne draw_chars4 - - ldi r18, 0x21 - draw_chars5: - mov HIGH_ACCUM, r18 - call draw_char - inc r18 - cpi r18, 0x7E - brne draw_chars5 - - ldi r18, 0x21 - draw_chars6: - mov HIGH_ACCUM, r18 - call draw_char - inc r18 - cpi r18, 0x7E - brne draw_chars6 + ldi r19, 12 + dctest: + ldi r18, 0x21 + draw_chars: + mov HIGH_ACCUM, r18 + call draw_char + inc r18 + cpi r18, 0x7E + brne draw_chars + dec r19 + brne dctest diff --git a/pat80-io-devices/composite-pal-adapter/software/avr-assembly/video_generator.asm b/pat80-io-devices/composite-pal-adapter/software/avr-assembly/video_generator.asm index 176ef21..24e5c5d 100644 --- a/pat80-io-devices/composite-pal-adapter/software/avr-assembly/video_generator.asm +++ b/pat80-io-devices/composite-pal-adapter/software/avr-assembly/video_generator.asm @@ -3,8 +3,12 @@ ; * Video generator module * ; ******************************************* +; Implemented following timings in http://blog.retroleum.co.uk/electronics-articles/pal-tv-timing-and-voltages/ +; Every line, for 52 times, it loads a byte from memory into PORTA register and then shifts the byte to the left to show another bit (do it 7 times) +; This also displays byte's MSB pixel "for free", as the video pin is PD7 (last bit of PORTA). + ; This module generates a Composite PAL monochrome signal with a resolution -; of 416x304 pixels of which only 376x232 pizels are visible (= 47x29 characters). +; of 416x304 pixels of which only 376x232 pizels are visible (= 46x29 characters). ; The signal is generated using 16-bit Timer1 and interrupts. @@ -25,6 +29,7 @@ .equ TIMER_DELAY_30US = 65535 - 690 ; 719 cycles @ 24Mhz (minus overhead) .equ TIMER_DELAY_2US = 65535 - 17 ; 48 cycles @ 24Mhz (minus overhead) +.equ BACK_PORCH_DELAY = 258 ; 186 cycles back porch + 72 cycles to leave 3 chunks empty (image padding) ; ********* FUNCTIONS CALLED BY INTERRUPT *********** @@ -77,14 +82,13 @@ draw_picture: ; **** start line back porch: 8uS, 192 cycles @ 24Mhz ; leave time at the end for line setup and draw_line call - ldi VG_HIGH_ACCUM, 62 ; 1 cycle + ldi VG_HIGH_ACCUM, BACK_PORCH_DELAY/3 ; 1 cycle l_sync_back_porch_loop: dec VG_HIGH_ACCUM ; 1 cycle brne l_sync_back_porch_loop ; 2 cycle if true, 1 if false ; **** end back porch call draw_line ; 3 cycles (+ 3 to come back to on_line_drawn) - ; **** draws line pixels: 52uS, 1248 cycles @ 24Mhz **** @@ -105,14 +109,13 @@ draw_picture: ; **** start line back porch: 8uS, 192 cycles @ 24Mhz ; leave time at the end for line setup and draw_line call - ldi VG_HIGH_ACCUM, 62 ; 1 cycle + ldi VG_HIGH_ACCUM, BACK_PORCH_DELAY/3 ; 1 cycle l_sync_back_porch_loop2: dec VG_HIGH_ACCUM ; 1 cycle brne l_sync_back_porch_loop2 ; 2 cycle if true, 1 if false ; **** end back porch call draw_line ; 3 cycles (+ 3 to come back to on_line_drawn) - ; **** draws line pixels: 52uS, 1248 cycles @ 24Mhz **** dec LINE_COUNTER ; decrement line countr ; 1 cycle brne h_picture_loop ; if not 0, repeat h_picture_loop ; 2 cycle if true, 1 if false @@ -192,7 +195,7 @@ short_sync: draw_line: ; NO loops, as this is time-strict - ; 52 chunks of 8 pixels + ; 46 chunks of 8 pixels ; chunk 1 ld A, X+ ; load pixel ; 2 cycles @@ -1344,154 +1347,12 @@ draw_line: lsr A ; 1 cycle out VIDEO_PORT_OUT, A ; 1 cycle - ; chunk 47 - ld A, X+ ; load pixel ; 2 cycles - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - - ; chunk 48 - ld A, X+ ; load pixel ; 2 cycles - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - - ; chunk 49 - ld A, X+ ; load pixel ; 2 cycles - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - - ; chunk 50 - ld A, X+ ; load pixel ; 2 cycles - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - - ; chunk 51 - ld A, X+ ; load pixel ; 2 cycles - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - - ; chunk 52 - ld A, X+ ; load pixel ; 2 cycles - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle - nop ; 1 cycle - lsr A ; 1 cycle - out VIDEO_PORT_OUT, A ; 1 cycle + ; chunk 47, 48, 49 (blank) + clr A ; 1 cycle + out VIDEO_PORT_OUT, A ; 1 cycle + ldi VG_HIGH_ACCUM, 23 ; 1 cycle + eol_porch_loop: ; requires 3 cpu cycles + dec VG_HIGH_ACCUM ; 1 cycle + brne eol_porch_loop ; 2 if jumps, 1 if continues ret