home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Dream 55
/
Amiga_Dream_55.iso
/
RISCOS
/
MAGAZINE
/
NEWS
/
PCE021.ZIP
/
Pce021
/
Src
/
s
/
video
< prev
Wrap
Text File
|
1998-07-24
|
29KB
|
1,159 lines
; video.s
; -------
; PC Engine video emulation
; by Paul Clifford
;
; Started 16 August 1997
GET hdr.SWINames
GET hdr.defines
^ 0
vdc_write_address # 4 ; 0x00
vdc_read_address # 4 ; 0x01
vdc_write * @ ; 0x02
vdc_read * @ ; 0x02
^ 0x05 * 4
vdc_control # 4 ; 0x05
vdc_raster_detect # 4 ; 0x06
vdc_bgx_scroll # 4 ; 0x07
vdc_bgy_scroll # 4 ; 0x08
vdc_memory_width # 4 ; 0x09
vdc_horizontal_period # 4 ; 0x0a
vdc_horizontal_display # 4 ; 0x0b
vdc_vertical_sync # 4 ; 0x0c
vdc_vertical_display # 4 ; 0x0d
vdc_vertical_end # 4 ; 0x0e
vdc_dma_control # 4 ; 0x0f
vdc_dma_source # 4 ; 0x10
vdc_dma_destination # 4 ; 0x11
vdc_dma_length # 4 ; 0x12
vdc_sprite_table # 4 ; 0x13
^ 0x20 * 4
vdc_bgy_counter # 4
vdc_display_rows # 4
vdc_event_mask # 4
vdc_status # 4
output_address # 4
output_line # 4
skip_frame # 4
ASSERT @ < 0x100
^ 0x100
cache_satb_count # (256 + 64 + 64) * 4
cache_satb_data # (256 + 64 + 64) * 16 * (4 + 8) * 2
vdc_size * @
^ 0
sprite_y # 2
sprite_x # 2
sprite_data # 2
sprite_flags # 2
sprite_size * @
;IRQ2 * 1 << 0 ; IRQ2, generated by BRK instruction
;IRQ1 * 1 << 1 ; IRQ1, general interrupt
;TIQ * 1 << 2 ; TIQ, timer interrupt
event_collision * 1 << 0 ; collision between sprite 0 and any other sprite
event_excess * 1 << 1 ; too many sprites on one scanline
event_coincide * 1 << 2 ; vdc_raster_detect = current raster
event_vram_satb * 1 << 3 ; VRAM-SATB transfer complete
event_vram_vram * 1 << 4 ; VRAM-VRAM transfer complete
event_retrace * 1 << 5 ; vertical retrace
enable_collision * 1 << 0 ; vdc_control (0x05)
enable_excess * 1 << 1 ; vdc_control (0x05)
enable_coincide * 1 << 2 ; vdc_control (0x05)
enable_retrace * 1 << 3 ; vdc_control (0x05)
enable_vram_satb * 1 << 0 ; vdc_dma_control (0x0f)
enable_vram_vram * 1 << 1 ; vdc_dma_control (0x0f)
; ------------------------------------------------------------------------
AREA |video$$code|, CODE, READONLY
; IMPORT irq_status
; IMPORT irq_mask
IMPORT vsync_flag
; void VDC_Initialise(void)
VDC_Initialise
EXPORT VDC_Initialise
ldr data, adrof_cpu_emulation_data
mov r0, #100 - 1 ; *
adr r1, Count_fps ; *
adrl r2, frame_counter ; *
swi OS_CallEvery ; *
mov r0, #0 ; *
str r0, frame_counter ; *
ldr r1, adrof_video_registers
mov r0, #0
str r0, [r1, #vdc_horizontal_period]
mov r0, #59
str r0, [r1, #vdc_horizontal_display]
b Resize_Screen
; void VDC_Finalise(void)
VDC_Finalise
EXPORT VDC_Finalise
adr r0, Count_fps
adrl r1, frame_counter
swi OS_RemoveTickerEvent
movs pc, r14
Count_fps
stmfd r13!, {r0-r1, r14}
ldr r1, [r12, #0]
mov r0, #0
str r0, [r12, #0]
adr r0, Display_fps
swi OS_AddCallBack
ldmfd r13!, {r0-r1, pc}^
Display_fps
stmfd r13!, {r0-r2, r14}
swi OS_WriteI + 31 ; move cursor
swi OS_WriteI + 0 ; x
swi OS_WriteI + 0 ; y
mov r0, r12
mov r2, #' '
orr r2, r2, r2, lsl #8
orr r2, r2, r2, lsl #16
stmfd r13!, {r2, r3}
add r1, r13, #4
mov r2, #4
swi OS_ConvertCardinal1
sub r2, r2, #1
sub r0, r0, r2
swi OS_Write0
add r13, r13, #8
ldmfd r13!, {r0-r2, pc}^
; void Cache_SATB(void)
Cache_SATB
stmfd r13!, {r4-r12, r14}
ldr r0, adrof_video_registers ; r0 = video registers
Cache_SATB_Entry
ldr r1, adrof_video_ram ; r1 = PCE video ram
mov r2, #65 ; r2 = sprite downcounter
ldr r3, [r0, #vdc_sprite_table]
mov r9, #0
add r3, r1, r3, lsl #1 ; r3 = halfword aligned address of satb
Cache_SATB_Next_Sprite
tst r9, #0x0100
ldmnefd r13!, {r4-r10}
bne Cache_SATB_Next_Strip
Cache_SATB_Next_Sprite_X
subs r2, r2, #1
ldmeqfd r13!, {r4-r12, pc}^
tst r3, #2_11
bicnes r4, r3, #2_11
ldmneia r4, {r4-r6}
ldmeqia r3, {r4-r5}
add r3, r3, #sprite_size ; move SATB pointer onto address of next sprite
add r7, r0, #cache_satb_count
add r8, r0, #cache_satb_data
movne r4, r4, lsr #16
orrne r4, r4, r5, lsl #16
bic r4, r4, #0xfc000000
bic r4, r4, #0x0000fc00
; r4 = 0xXXXXYYYY (YYYY = Y coord, XXXX = X coord)
movne r5, r5, lsr #16
orrne r5, r5, r6, lsl #16
; r5 = 0xFFFFVVVV (FFFF = flags, VVVV = vram offset >> 6)
mov r10, r5, lsl #16 + 5 ; r10 = 0xVVVV0000 (+5 to clear rubbish from upper 5 bits)
mov r10, r10, lsr #16 - 1 ; r10 = 0x0000VVVV
mov r9, r4, lsr #16 ; r9 = 0x0000XXXX
mov r9, r9, lsl #16 ; r9 = 0xXXXX0000
bic r6, r4, r9 ; r6 = 0x0000YYYY
sub r4, r6, #256
cmp r4, #320 - 256 ; is y outside maximum visible area?
bgt Cache_SATB_Next_Sprite_X ; yes
orr r9, r9, r5, lsr #16 ; r9 = 0xXXXXFFFF
teqp pc, r9, lsl #16 ; N = flipped up-down, C = 4 x height, V = 2 x height
mov r4, #0x10
movvs r4, #0x20
movcs r4, #0x40 ; r4 = height
addmi r10, r10, #0x1e
submi r11, r4, #0x10
addmi r10, r10, r11, lsl #4
tst r9, #0x0100 ; width x 2?
bicne r10, r10, #0x80
tstne r9, #0x0800 ; && flipped left-right?
orrne r10, r10, #0x80
add r10, r10, r1 ; r10 = start (or end) of sprite data
add r7, r7, r6, lsl #2 ; r7 = cache_satb_count for first line
add r8, r8, r6, lsl #9
sub r8, r8, r6, lsl #7 ; r8 = cache_satb_data for first line
tst r9, #0x0080
addeq r8, r8, #192 ; adjust r8 if sprite is in the foreground
sub r8, r8, #384
sub r4, r4, #1
mvn r5, #1
tst r9, #0x8000
subeq r10, r10, #2
addne r10, r10, #2
tst r9, #0x0100
bicne r11, r9, #0x00000100
addne r11, r11, #0x00100000
eorne r12, r10, #0x80
stmnefd r13!, {r4-r8, r11, r12}
Cache_SATB_Next_Strip
ldr r11, [r7], #4
add r8, r8, #384
tst r4, #2_1111
movne r12, #2
moveq r12, #2 + (0x100 - 32)
sub r4, r4, #1
tst r9, #0x8000
addeq r10, r10, r12
subne r10, r10, r12
tst r11, r11, lsr #6 ; excess strips on this line?
teqcs r4, r5
bhi Cache_SATB_Next_Strip ; excess strips && ~final line
bcs Cache_SATB_Next_Sprite ; excess strips && final line
tst r9, #0x0080
addeq r11, r11, #1 << 16 ; foreground
addne r11, r11, #1 << 24 ; background
tst r11, r11, lsr #5
orrcs r12, r11, #2_100000 ; mark as having too many strips to display
addcc r12, r11, #1
str r12, [r7, #-4]
teqcs r4, r5
bhi Cache_SATB_Next_Strip
bcs Cache_SATB_Next_Sprite
tst r9, #0x0080
moveq r11, r11, lsl #8
tst r10, r10, lsr #2
biccs r10, r10, #2_10
ldr r12, [r10, #0x00]
mov r11, r11, lsr #24 - 2
add r11, r11, r11, lsl #1
ldr r14, [r10, #0x20]
movcs r12, r12, lsr #16 ; r12 = ????pln1
mov r12, r12, lsl #16 ; r12 = pln10000
str r9, [r11, r8]! ; store X coordinate and flags
movcc r14, r14, lsl #16 ; r14 = pln2????
orr r12, r12, r14, lsr #16 ; r12 = pln1pln2
str r12, [r11, #4] ; store planes 1 and 2
ldr r12, [r10, #0x40]
teq r4, r5
ldr r14, [r10, #0x60]
movcs r12, r12, lsr #16 ; r12 = ????pln3
mov r12, r12, lsl #16 ; r12 = pln30000
movcc r14, r14, lsl #16 ; r14 = pln4????
orr r12, r12, r14, lsr #16 ; r12 = pln3pln4
str r12, [r11, #8] ; store planes 3 and 4
orrcs r10, r10, #2_10
bne Cache_SATB_Next_Strip
b Cache_SATB_Next_Sprite
; void Read_Sprite_Table(void)
Read_Sprite_Table
stmfd r13!, {r0-r12, r14}
ldr r0, =vsync_flag
ldr r1, [r0, #4]
cmp r1, #1
ldrlt r1, [r0, #4]
sublt pc, pc, #16
rsbgts r14, r1, #8
sub r1, r1, #1
str r1, [r0, #4]
ldr r0, adrof_video_registers
movgt r14, #1
movle r14, #0
str r14, [r0, #skip_frame]
ldr r14, frame_counter
add r14, r14, #1
str r14, frame_counter
; mov r3, #0 ; r3 = background plane
Read_Sprite_Table_Plane
ldr r0, adrof_video_registers
ldr r1, adrof_video_ram ; r1 = video ram
ldr r0, [r0, #vdc_sprite_table] ; r0 = offset of sprite table
mov r2, #64 ; r2 = sprite downcounter
add r0, r1, r0, lsl #1 ; r0 = address of sprite table
b Read_Outer_Entry
Read_Outer_Loop
subs r2, r2, #1
; ble Read_Sprite_Table_End
ldmlefd r13!, {r0-r12, pc}^
add r0, r0, #sprite_size
Read_Outer_Entry
add r5, r0, #sprite_flags
ands r6, r5, #2_11
ldr r5, [r5, -r6]
add r6, r0, #sprite_data
moveq r5, r5, lsl #16
mov r5, r5, lsr #16 ; r5 = flag bytes
movs r4, r5, lsl #16 + 3
movpl r4, #0x10 ; normal height
movmi r4, #0x20 ; height x 2
movcs r4, #0x40 ; height x 4
; r4 = sprite height in pixels
; and r6, r5, r3
; cmp r6, r3 ; is sprite in the current plane?
ands r7, r6, #2_11
add r8, r0, #sprite_x
ldr r6, [r6, -r7]
movne r6, r6, lsr #16
tst r5, #0x8000 ; flipped up-down?
mov r6, r6, lsl #21
mov r6, r6, lsr #15
; r6 = VRAM byte offset to sprite data
addne r6, r6, #0x1e ; yes
subne r7, r4, #0x10
addne r6, r6, r7, lsl #4 ; skip however many tiles
ands r7, r8, #2_11
ldr r7, [r8, -r7]
add r8, r0, #sprite_y
moveq r7, r7, lsl #16
mov r7, r7, lsr #16 ; r7 = sprite x
ands r9, r8, #2_11
ldr r8, [r8, -r9]
moveq r8, r8, lsl #16
mov r8, r8, lsr #16
tst r5, #0x0100 ; width x 2?
bicne r6, r6, #0x80
tstne r5, #0x0800 ; width x 2 && flipped left-right?
orrne r6, r6, #0x80
cmp r7, #512 ; is x outside maximum visible area?
bgt Read_Outer_Loop ; yes
sub r9, r8, #256
cmp r9, #320 - 256 ; is y outside maximum visible area?
bgt Read_Outer_Loop ; yes
ldr r9, adrof_sprite_cache_count
orr r5, r5, r7, lsl #16 ; r5 = xxxxffff (x = sprite x, f = flags)
ldr r10, adrof_sprite_cache_info
add r9, r9, r8, lsl #2 ; r9 = cache_count[...
ldr r11, adrof_sprite_cache_data
add r10, r10, r8, lsl #6 ; r10 = cache_info[line][...
add r11, r11, r8, lsl #6 ; r11 = cache_data[line][...
sub r4, r4, #1
Read_Inner_Loop
ldr r7, [r9, #0]
add r8, r7, #1
str r8, [r9], #4 ; increment no. of sprites on this line
cmp r7, #16
strlt r6, [r11, r7, lsl #2]
add r11, r11, #1 << 6 ; cache_data[line++]
strlt r5, [r10, r7, lsl #2]
add r10, r10, #1 << 6 ; cache_info[line++]
tst r4, #2_1111
movne r7, #2
moveq r7, #2 + (0x100 - 32)
tst r5, #0x8000 ; flipped up-down?
addeq r6, r6, r7 ; no, so data += offset
subne r6, r6, r7 ; yes, so data -= offset
subs r4, r4, #1
bge Read_Inner_Loop
subs r2, r2, #1
addgt r0, r0, #sprite_size
bgt Read_Outer_Entry
Read_Sprite_Table_End
ldmfd r13!, {r0-r12, pc}^
; void Update_Line(void)
Update_Line
stmfd r13!, {r0-r12, r14}
ldr r14, adrof_physical_screen_width
cmp r2, #64
ldr r14, [r14, #0]
ldreq r1, adrof_physical_screen
ldrne r1, [r0, #output_address]
ldreq r1, [r1, #0]
add r14, r14, r1
str r14, [r0, #output_address]
ldrne r2, [r0, #vdc_bgy_counter]
ldreq r2, [r0, #vdc_bgy_scroll]
add r2, r2, #1
str r2, [r0, #vdc_bgy_counter]
stmfd r13!, {r1}
ldr r3, [r0, #vdc_control]
tst r3, #0x0080 ; background on?
beq No_Background
add r1, r1, #32
; find the dimensions of the virtual screen
ldr r3, [r0, #vdc_memory_width]
teqp pc, r3, lsl #24 + 1
; convert the y scroll into number of tiles from top of map
mov r4, r2, lsr #3
and r2, r2, #7
; and mask this value against the virtual screen height
ldr r6, adrof_video_ram
andmi r4, r4, #64 - 1 ; BG map is 64 tiles high
andpl r4, r4, #32 - 1 ; BG map is 32 tiles high
; then calculate the address of the relevant part of the background map
add r5, r6, r4, lsl #5 + 1 ; BG map is 32 tiles wide
addhi r5, r6, r4, lsl #6 + 1 ; BG map is 64 tiles wide
addeq r5, r6, r4, lsl #7 + 1 ; BG map is 128 tiles wide
; make a mask for the horizontal tile index
mov r4, #(1 << 5) - 1
movhi r4, #(1 << 6) - 1
moveq r4, #(1 << 7) - 1
; calculate the number of tiles that need to be processed to form a line of output
ldr r6, [r0, #vdc_bgx_scroll]
ldrb r7, [r0, #vdc_horizontal_display]
tst r6, #2_100
orr r4, r4, r7, lsl #17 ; combine tile no. mask and horizontal no. of tiles
add r4, r4, #1 << 17
orrne r4, r4, #1 << 15 ; skip the first half tile?
ands r12, r6, #2_11
orrne r4, r4, #1 << 14 ; need to clip the display
addne r4, r4, #1 << 16 ; if clipping, we need to use an extra half tile
rsbne r12, r12, #4
movne r12, r12, lsl #3 ; shift for "word"
rsb r10, r12, #32
orr r12, r12, r10, lsl #8 ; shift for "previous_word"
; convert the x scroll into a tile index, then mask against the virtual screen width
mov r6, r6, lsr #3
and r6, r6, r4 ; , lsr #8
; initialise the read cache if necessary
tst r6, #1
addne r14, r5, r6, lsl #1
ldrne r8, [r14, #-2]
; setup register to contain the 0x80808080 mask
mov r10, #0x80
orr r10, r10, r10, lsl #8
orr r10, r10, r10, lsl #16
; cache background colour 0
ldr r14, adrof_background_vce
ldrb r14, [r14, #0]
orr r14, r12, r14, lsl #24
mov r12, #0
VDC_Draw_Line_Loop
; get the current tile information from the background map
tst r6, #1
ldreq r8, [r5, r6, lsl #1]
movne r8, r8, lsr #16
; increment the tile number and mask it
add r6, r6, #1
and r6, r6, r4 ; , lsr #8
; shift the tile palette and address to the upper 16 bits to lose the unncessary bits above
mov r9, r8, lsl #16
; extract the tile palette
mov r11, r9, lsr #28
; calculate the actual tile data address
ldr r7, adrof_video_ram
bic r9, r9, r11, lsl #28 ; lose the tile palette
add r9, r7, r9, lsr #16 - 5 ; shift to get ARM address offset
; read the planar tile data and find the address of the tile palette
ldr r7, [r9, r2, lsl #1]!
mov r11, r11, lsl #6
ldr r9, [r9, #16]
mov r7, r7, lsl #16 ; 0xp2p10000
mov r9, r9, lsl #16 ; 0xp4p30000
orr r7, r9, r7, lsr #16 ; 0xp4p3p2p1
ldr r9, adrof_background_vce
tst r4, #1 << 15
movne r7, r7, lsl #4
add r11, r11, r9
VDC_Draw_BGTile_Loop
; convert four pixels from planar to chunky format
ands r9, r10, r7 ; pixel 1
orrne r9, r9, r9, lsl #7
orrne r9, r9, r9, lsl #14
movnes r9, r9, lsr #28 - 2
ldrneb r9, [r11, r9]
moveq r9, r14, lsr #24
ands r3, r10, r7, lsl #1 ; pixel 2
orrne r3, r3, r3, lsl #7
orrne r3, r3, r3, lsl #14
movnes r3, r3, lsr #28 - 2
ldrneb r3, [r11, r3]
moveq r3, r14, lsr #24
orr r9, r9, r3, lsl #8
ands r3, r10, r7, lsl #2 ; pixel 3
orrne r3, r3, r3, lsl #7
orrne r3, r3, r3, lsl #14
movnes r3, r3, lsr #28 - 2
ldrneb r3, [r11, r3]
moveq r3, r14, lsr #24
orr r9, r9, r3, lsl #16
ands r3, r10, r7, lsl #3 ; pixel 4
orrne r3, r3, r3, lsl #7
orrne r3, r3, r3, lsl #14
movnes r3, r3, lsr #28 - 2
ldrneb r3, [r11, r3]
moveq r3, r14, lsr #24
orr r9, r9, r3, lsl #24
tst r4, #1 << 14 ; clip this half tile?
orreq r3, r12, r9, lsl r14
bicne r4, r4, #1 << 14 ; yep, but don't clip any others
streq r3, [r1], #4
mov r3, r14, lsr #8
mov r12, r9, lsr r3
eor r4, r4, #1 << 15
sub r4, r4, #1 << 16
movs r3, r4, lsr #16
movcs r7, r7, lsl #4
bhi VDC_Draw_BGTile_Loop
bne VDC_Draw_Line_Loop
ldr r3, [r0, #vdc_control]
tst r3, #0x0040 ; sprites on?
addeq r13, r13, #4
ldmeqfd r13!, {r0-r12, pc}^
Update_Sprites
ldmfd r13!, {r2}
ldr r1, [r0, #output_line]
ldr r0, adrof_sprite_cache_count
; add r1, r1, #64 ; r1 = raster
ldr r3, adrof_sprite_cache_info
ldr r4, [r0, r1, lsl #2]
mov r5, #0
str r5, [r0, r1, lsl #2]
add r3, r3, r1, lsl #6
ldr r0, adrof_sprite_cache_data
cmp r4, #16
blgt Sprite_Excess
; r4-r7, r14 are corrupted if r4 > 16
movgt r4, #16
cmp r4, #0
ldmeqfd r13!, {r0-r12, pc}^
add r0, r0, r1, lsl #6
ldr r1, adrof_video_ram
add r0, r0, r4, lsl #2
add r3, r3, r4, lsl #2
; r0 = sprite_cache_data[raster][...
; r1 = address of PCE video RAM
; r2 = output base
; r3 = sprite_cache_info[raster][...
; r4 = sprites on line (always >= 1)
Update_Sprites_Loop
ldr r5, [r3, #-4]! ; r5 = xxxxffff (x = sprite x, f = flags)
ldr r6, [r0, #-4]! ; r6 = data address
add r10, r2, r5, lsr #16 ; r10 = address to output sprite line to
ldr r7, adrof_sprite_vce
and r8, r5, #0xf
add r11, r7, r8, lsl #4 + 2 ; r11 = address of sprite palette
Update_Sprites_Setup
add r7, r1, r6 ; r7 = half-word aligned address of sprite data
movs r7, r7, lsr #2
mov r7, r7, lsl #2
ldr r8, [r7, #0x00]
eor r6, r6, #0x80
ldr r9, [r7, #0x20]
movcs r8, r8, lsr #16
mov r8, r8, lsl #16 ; r8 = pln10000
movcc r9, r9, lsl #16 ; r9 = pln2????
orr r8, r8, r9, lsr #16 ; r8 = pln1pln2
ldr r9, [r7, #0x60]
mov r12, #1 << 15
ldr r7, [r7, #0x40]
movcc r9, r9, lsl #16 ; r9 = pln4????
mov r9, r9, lsr #16 ; r9 = 0000pln4
movcs r7, r7, lsr #16 ; r7 = ????pln3
orr r9, r9, r7, lsl #16 ; r9 = pln3pln4
; r7 free
tst r5, #0x0800 ; flipped left-right?
bic r5, r5, #0x1f
moveq r8, r8, ror #1 ; no
moveq r9, r9, ror #1
orreq r5, r5, #31
movne r8, r8, ror #16 ; yes
movne r9, r9, ror #16
orrne r5, r5, #1
Update_Sprites_Plot
movs r8, r8, ror r5
subpl r7, r11, #1
addmi r7, r11, #(2_0001 << 2) - 1
tst r8, r8, lsl #16 + 1
addcs r7, r7, #2_0010 << 2
movs r9, r9, ror r5
addmi r7, r7, #2_0100 << 2
tst r9, r9, lsl #16 + 1
addcs r7, r7, #2_1000 << 2
cmp r7, r11 ; carry clear if r7 < r11 (ie pixel is transparent)
ldrcsb r7, [r7, #1]
addcc r10, r10, #1
; movcs r7, r7, lsr #1
strcsb r7, [r10], #1
movs r12, r12, lsr #1
bcc Update_Sprites_Plot
tst r5, #0x0100
bicne r5, r5, #0x0100
bne Update_Sprites_Setup
subs r4, r4, #1
bhi Update_Sprites_Loop
ldmfd r13!, {r0-r12, pc}^
No_Background
ldrb r4, [r0, #vdc_horizontal_display]
mov r5, #0
mov r6, #0
mov r7, #0
mov r8, #0
add r9, r1, #32
No_Background_Loop
stmia r9!, {r5-r8}
subs r4, r4, #2
stmgeia r9!, {r5-r8}
subges r4, r4, #2
stmgeia r9!, {r5-r8}
subges r4, r4, #2
stmgeia r9!, {r5-r8}
subges r4, r4, #2
stmgeia r9!, {r5-r8}
subges r4, r4, #2
stmgeia r9!, {r5-r8}
subges r4, r4, #2
stmgeia r9!, {r5-r8}
subges r4, r4, #2
stmgeia r9!, {r5-r8}
subges r4, r4, #2
bge No_Background_Loop
tst r3, #0x0040 ; sprites on?
bne Update_Sprites
add r13, r13, #4
ldmfd r13!, {r0-r12, pc}^
Sprite_Excess
ldr r5, adrof_video_registers
ldr r6, [r5, #vdc_status]
orr r6, r6, #event_excess
str r6, [r5, #vdc_status] ; set VDC event high
movs pc, r14
; void Increment_Raster(void)
; Move onto next raster line
Increment_Raster
EXPORT Increment_Raster
ldr r0, adrof_video_registers
stmfd r13!, {r14}
ldr r2, [r0, #output_line] ; current line (visible area starts at 64)
ldr r3, [r0, #vdc_vertical_display] ; lower 9 bits = visible height - 1
sub r14, r2, #64
cmp r14, r3 ; within visible area?
ldrlo r14, [r0, #skip_frame]
cmplo r14, #1 ; yes: and not skipping this frame?
bllo Update_Line ; yes: draw the line
mov r1, #0 ; new VDC events
add r2, r2, #1 ; increment the raster
ldrb r14, [r0, #vdc_vertical_end] ; vertical front porch
add r3, r3, #65 ; line on which display ends
add r3, r3, r14 ; line on which vsync is generated
cmp r2, r3
ldr r14, [r0, #vdc_vertical_sync] ; bits 4:0 = vsync width, 15:8 = vertical back porch
orreq r1, r1, #event_retrace
mov r14, r14, ror #5
add r3, r3, r14, lsr #32 - 5 ; line on which wrap-around occurs
cmp r2, r3
moveq r14, r14, ror #32 - 5
rsbeq r14, r14, #62 << 8
ldr r3, [r0, #vdc_raster_detect] ; line on which coincidence event occurs
moveq r2, r14, asr #8
bleq Read_Sprite_Table
str r2, [r0, #output_line] ; update current line
cmp r2, r3 ; time for coincidence event?
ldr r2, [r0, #vdc_status]
orreq r1, r1, #event_coincide ; yes: generate coincidence event
ldr r14, [r0, #vdc_event_mask]
orr r2, r2, r1
str r2, [r0, #vdc_status]
tst r2, r14 ; generate an IRQ?
orrne r_p, r_p, #IRQ1 << 16 ; yes
ldmfd r13!, {pc}^
frame_counter ; *
DCD 0 ; *
; void VDC_Write(uhalf address, ubyte value)
; Video Display Controller write port
VDC_Write
EXPORT VDC_Write
movs r2, r0
mov r0, r1 ; VDC_Write_x functions expect value in r0
beq VDC_Write_0
cmp r2, #2
beq VDC_Write_2
cmp r2, #3
movnes pc, r14
; void VDC_Write_3(ubyte value)
; Write upper byte of data to VDC address
VDC_Write_3
EXPORT VDC_Write_3
ldr r2, adrof_vdc_address
adr r3, vdc_write_3_mask
ldr r2, [r2, #0] ; r2 = VDC address
ldr r1, adrof_video_registers ; r1 = video registers
ldrb r3, [r3, r2] ; r3 = mask value
cmp r2, #vdc_dma_length >> 2
and r0, r0, r3 ; r0 = masked write value
add r3, r1, #1
strb r0, [r3, r2, lsl #2] ; store value in register
beq VRAM_VRAM_Transfer
cmp r2, #vdc_sprite_table >> 2
beq VRAM_SATB_Transfer
cmp r2, #vdc_bgy_scroll >> 2
; moveqs pc, r14
cmp r2, #vdc_bgy_scroll >> 2
; mvneq r0, #0
; streq r0, [r1, #vdc_bgy_counter]
streqb r0, [r3, #vdc_bgy_counter]
moveqs pc, r14
cmp r2, #vdc_horizontal_period >> 2
cmpne r2, #vdc_horizontal_display >> 2
beq Update_Video_Timing
cmp r2, #vdc_write >> 2
ldreq r2, [r1, #vdc_write_address]
movnes pc, r14
ldr r3, adrof_video_ram
ldr r0, [r1, #vdc_write]
mov r2, r2, lsl #16
strb r0, [r3, r2, lsr #15]!
mov r0, r0, lsr #8
strb r0, [r3, #1]
ldr r0, [r1, #vdc_control]
and r0, r0, #3 << 11
cmp r0, #1 << 11
addlt r2, r2, #0x01 << 16
addeq r2, r2, #0x20 << 16
cmp r0, #2 << 11
addeq r2, r2, #0x40 << 16
addgt r2, r2, #0x80 << 16
mov r2, r2, lsr #16
str r2, [r1, #vdc_write_address]
movs pc, r14
vdc_write_3_mask
= 0xff, 0xff, 0xff, 0x00 ; 0x00-0x03
= 0x00, 0x1f, 0x03, 0x03 ; 0x04-0x07
= 0x01, 0x00, 0x7f, 0x7f ; 0x08-0x0b
= 0xff, 0x01, 0x00, 0x00 ; 0x0c-0x0f
= 0xff, 0xff, 0xff, 0xff ; 0x10-0x13
; void VDC_Write_0(ubyte value)
; Set VDC address
VDC_Write_0
EXPORT VDC_Write_0
ldr r1, adrof_vdc_address
and r0, r0, #0x1f
str r0, [r1, #0]
movs pc, r14
; void VDC_Write_2(ubyte value)
; Write lower byte of data to VDC address
VDC_Write_2
EXPORT VDC_Write_2
ldr r2, adrof_vdc_address
adr r3, vdc_write_2_mask
ldr r2, [r2, #0] ; r2 = VDC address
ldr r1, adrof_video_registers ; r1 = video registers
ldrb r3, [r3, r2] ; r3 = write mask
cmp r2, #vdc_bgy_scroll >> 2
and r0, r0, r3 ; r0 = masked value
strb r0, [r1, r2, lsl #2]
; mvneq r0, #0
; streq r0, [r1, #vdc_bgy_counter]
streqb r0, [r1, #vdc_bgy_counter]
moveqs pc, r14
cmp r2, #vdc_vertical_display >> 2
cmpne r2, #vdc_horizontal_display >> 2
beq Resize_Screen
cmp r2, #vdc_horizontal_period >> 2
beq Update_Video_Timing
cmp r2, #vdc_control >> 2
cmpne r2, #vdc_dma_control >> 2
movnes pc, r14
ldr r3, [r1, #vdc_event_mask]
tst r0, r0, lsr #4
teq r2, #vdc_dma_control >> 2
andeq r0, r0, #2_000011
moveq r0, r0, lsl #3
andne r0, r0, #2_000111
orrhi r0, r0, #2_100000 ; not vdc_dma_control and bit 4 of r0 set
biceq r3, r3, #2_011000
bicne r3, r3, #2_100111
orr r3, r3, r0
str r3, [r1, #vdc_event_mask]
movs pc, r14
vdc_write_2_mask
= 0xff, 0xff, 0xff, 0x00 ; 0x00-0x03
= 0x00, 0xff, 0xff, 0xff ; 0x04-0x07
= 0xff, 0xff, 0x1f, 0x7f ; 0x08-0x0b
= 0x1f, 0xff, 0xff, 0x1f ; 0x0c-0x0f
= 0xff, 0xff, 0xff, 0xff ; 0x10-0x13
VRAM_SATB_Transfer
ldr r0, [r1, #vdc_status]
ldr r3, [r1, #vdc_event_mask]
orr r0, r0, #event_vram_satb
str r0, [r1, #vdc_status]
tst r0, r3
orrne r_p, r_p, #IRQ1 << 16
movs pc, r14
; r1 = video registers
; r2 = VDC address
VRAM_VRAM_Transfer
stmfd r13!, {r4-r10}
ldr r3, [r1, #vdc_dma_control]
ldr r0, [r1, #vdc_dma_source] ; r0 = VRAM source address
tst r3, #1 << 3
ldr r2, [r1, #vdc_dma_destination] ; r2 = VRAM destination address
mov r0, r0, lsl #17
mov r2, r2, lsl #17
mvnne r4, #0
moveq r4, #1
; r4 = source increment
ldr r6, adrof_video_ram ; r6 = video ram lower bytes
tst r3, #1 << 2
ldr r7, [r1, #vdc_dma_length] ; r7 = length of transfer
mvnne r5, #0
moveq r5, #1
; r5 = destination increment
add r8, r6, #1 ; r8 = video ram upper bytes
VRAM_VRAM_Loop
ldrb r9, [r6, r0, lsr #16]
ldrb r10, [r8, r0, lsr #16]
add r0, r0, r4, lsl #17
strb r9, [r6, r2, lsr #16]
strb r10, [r8, r2, lsr #16]
add r2, r2, r5, lsl #17
subs r7, r7, #1
bgt VRAM_VRAM_Loop
ldmfd r13!, {r4-r10}
ldr r2, [r1, #vdc_status]
orr r2, r2, #event_vram_vram
str r2, [r1, #vdc_status] ; set VDC event high
movs pc, r14
Resize_Screen
stmfd r13!, {r7, r14}
bl Update_Video_Timing
mov r7, r1
ldrb r0, [r1, #vdc_horizontal_display]
mov r2, #640
mov r3, #480
ldr r1, adrof_mode_block
cmp r0, #(480 >> 3) - 1
movle r2, #480
movle r3, #352
cmp r0, #(320 >> 3) - 1
ldmib r1, {r0, r14}
movle r2, #320
movle r3, #256
cmp r0, r2
cmpeq r14, r3
ldmeqfd r13!, {r7, pc}^
stmib r1, {r2-r3}
mov r0, #0
swi OS_ScreenMode
swi OS_RemoveCursors
adr r0, vdu_variable
ldr r1, adrof_physical_screen
swi OS_ReadVduVariables
ldr r1, adrof_physical_screen
ldr r0, [r1, #0]
str r0, [r7, #output_address]
; ldr r1, adrof_output_address
; str r0, [r1, #0]
mvn r0, #0
mov r1, #6
swi OS_ReadModeVariable
ldr r0, adrof_physical_screen_width
str r2, [r0, #0]
mov r2, #255
Set_Palette
swi OS_WriteI + 19
mov r0, r2
swi OS_WriteC ; colour number
swi OS_WriteI + 16
and r0, r2, #31
mov r0, r0, lsl #3
add r0, r0, r2, lsr #5
swi OS_WriteC ; red
mov r0, r2
swi OS_WriteC ; green
and r0, r2, #3
mov r0, r0, lsl #6
add r0, r0, r2, lsr #2
swi OS_WriteC ; blue
subs r2, r2, #1
bge Set_Palette
ldmfd r13!, {r7, pc}^
vdu_variable
DCD 148
DCD -1
Update_Video_Timing
stmfd r13!, {r1, r14}
ldr r0, [r1, #vdc_vertical_sync]
ldr r2, [r1, #vdc_vertical_display]
ldr r3, [r1, #vdc_vertical_end]
bic r2, r2, #2_11111110 << 8
and r3, r3, #2_11111111
add r2, r2, r3
add r2, r2, r0, lsr #8
and r3, r0, #2_00011111
ldr r0, video_divider
add r2, r2, r3
add r2, r2, #4 ; r2 = vertical height
str r2, [r1, #vdc_display_rows]
add r1, r2, r2, lsl #1
mov r2, #0
adds r0, r0, r0
rsb r1, r1, #0
mov r3, #32
Division_Loop
adcs r2, r1, r2, lsl #1
subcc r2, r2, r1
adcs r0, r0, r0
adcs r2, r1, r2, lsl #1
subcc r2, r2, r1
adcs r0, r0, r0
adcs r2, r1, r2, lsl #1
subcc r2, r2, r1
adcs r0, r0, r0
adcs r2, r1, r2, lsl #1
subcc r2, r2, r1
adcs r0, r0, r0
sub r3, r3, #4
teq r3, #0
bne Division_Loop
mov timer, timer, lsr #16
orr timer, r0, timer, lsl #16
ldmfd r13!, {r1, pc}^
video_divider
DCD 358000
; ubyte VDC_Read(uhalf address)
; Video Display Controller read port
VDC_Read
EXPORT VDC_Read
ldr r1, adrof_video_registers
cmp r0, #1
moveq r0, #0
ldrlt r2, [r1, #vdc_status]
moveqs pc, r14
blt VDC_Read_Status
cmp r0, #3
movgts pc, r14
; ldr r2, adrof_vdc_address
; ldr r2, [r2, #0]
; cmp r2, #3
; bne VDC_Read_X
; cmp r0, #3
ldr r3, [r1, #vdc_read_address]
ldr r2, adrof_video_ram
mov r3, r3, lsl #16
addeq r2, r2, #1
ldrb r0, [r2, r3, lsr #15]
ldreq r2, [r1, #vdc_control]
movlts pc, r14
and r2, r2, #3 << 11
cmp r2, #1 << 11
addlt r3, r3, #0x01 << 16
addeq r3, r3, #0x20 << 16
cmp r2, #2 << 11
addeq r3, r3, #0x40 << 16
addgt r3, r3, #0x80 << 16
mov r3, r3, lsr #16
str r3, [r1, #vdc_read_address]
movs pc, r14
VDC_Read_Status
ldr r3, [r1, #vdc_event_mask]
and r0, r2, r3
; orr r3, r0, r0, lsr #1
; orr r3, r3, r3, lsr #2
; orr r3, r3, r3, lsr #3
; bic r3, r0, r3
bic r2, r2, r3
str r2, [r1, #vdc_status]
movs pc, r14
;VDC_Read_X
; ldr r0, [r1, r0, lsl #2]
; movs pc, r14
; void VCE_Write(uhalf address, ubyte value)
; Video Colour Encoder write port
VCE_Write
EXPORT VCE_Write
cmp r0, #1
ldrlt r2, adrof_dot_width
andlt r1, r1, #1
strlt r1, [r2, #0]
movles pc, r14
cmp r0, #3
ldr r2, adrof_vce_address
andeq r1, r1, #1
strltb r1, [r2, #0]
streqb r1, [r2, #1]
movles pc, r14
cmp r0, #5
movgts pc, r14
ldr r3, [r2, #0]
mov r3, r3, lsl #23
addeq r0, r3, #1 << 23
moveq r0, r0, lsr #23
streq r0, [r2, #0]
ldr r2, adrof_background_vce
moveq r1, r1, lsl #8
ldr r0, [r2, r3, lsr #21]!
mov r3, #0xff00
bicne r0, r0, r3, ror #1 + 8
biceq r0, r0, r3, ror #1
orr r0, r0, r1, ror #1
str r0, [r2, #0]
movs pc, r14
; ubyte VCE_Read(uhalf address)
; Video Colour Encoder read port
VCE_Read
EXPORT VCE_Read
cmp r0, #1
movle r0, #0
movles pc, r14
ldr r1, adrof_vce_address
cmp r0, #3
ldrltb r0, [r1, #0]
ldreqb r0, [r1, #1]
movles pc, r14
cmp r0, #5
movgts pc, r14
ldr r2, [r1, #0]
ldr r3, adrof_background_vce
mov r2, r2, lsl #23
ldr r0, [r3, r2, lsr #21]
mov r0, r0, ror #32 - 1
moveq r0, r0, lsr #8
andlt r0, r0, #0xff
movlts pc, r14
add r2, r2, #1 << 23
mov r2, r2, lsr #23
str r2, [r1, #0]
movs pc, r14
adrof_cpu_emulation_data
IMPORT cpu_emulation_data
DCD cpu_emulation_data
adrof_dot_width
DCD dot_width
adrof_background_line
DCD background_line
;adrof_output_line
; DCD output_line
adrof_physical_screen
DCD physical_screen
adrof_physical_screen_width
DCD physical_screen_width
adrof_vdc_address
DCD vdc_address
adrof_vce_address
DCD vce_address
adrof_mode_block
DCD mode_block
adrof_video_ram
DCD video_ram
adrof_sprite_cache_count
DCD sprite_cache_count
adrof_sprite_cache_info
DCD sprite_cache_info
adrof_sprite_cache_data
DCD sprite_cache_data
adrof_video_registers
DCD video_registers
adrof_background_vce
DCD background_vce
adrof_sprite_vce
DCD sprite_vce
;adrof_irq_status
; DCD irq_status
;adrof_irq_mask
; DCD irq_mask
; ------------------------------------------------------------------------
AREA |video$$data|, DATA
dot_width
EXPORT dot_width
DCD 0
background_line
EXPORT background_line
DCD 0
;output_line
; EXPORT output_line
; DCD 0
vdc_address
EXPORT vdc_address
DCD 0
vce_address
EXPORT vce_address
DCD 0
physical_screen
EXPORT physical_screen
DCD physical_screen
physical_screen_width ; must follow physical_screen
EXPORT physical_screen_width
DCD physical_screen_width
mode_block
EXPORT mode_block
DCD 1
DCD -1
DCD -1
DCD 3
DCD -1
DCD 0
DCD 128
DCD 3
DCD 255
DCD -1
; ------------------------------------------------------------------------
AREA |video$$zidata|, NOINIT
video_ram
EXPORT video_ram
% 0x20000
sprite_cache_count
EXPORT sprite_cache_count
% (256 + 64 + 64) * 4
sprite_cache_info
EXPORT sprite_cache_info
% (256 + 64 + 64) * 16 * 4
sprite_cache_data
EXPORT sprite_cache_data
% (256 + 64 + 64) * 16 * 4
video_registers
EXPORT video_registers
% vdc_size
background_vce
EXPORT background_vce
% 256 * 4
; sprite_vce MUST follow background_vce
sprite_vce
EXPORT sprite_vce
% 256 * 4
END