PHP код:
; ZXScreen module by Wilbert
; *SCR has to be 6912 bytes of ZX Spectrum screen
; *Target has to be a buffer for 32 bit color data
; When FlashState is set to 1, pen and ink will be
; switched for blocks that have the flash bit set.
DeclareModule ZXScreen
Declare RenderSCR(*SCR, *Target, FlashState = 0)
EndDeclareModule
Module ZXScreen
#FlipY = #True
#SwapRB = #True
EnableExplicit
DisableDebugger ; disabling debugger is required !!
EnableASM
;- Data section
DataSection
ColorLUT:
Data.l $ff000000,$ffc03020,$ff1040c0,$ffc040c0,$ff10b040,$ffb0c050,$ff10c0e0,$ffc0c0c0
Data.l $ff000000,$ffff4030,$ff3040ff,$fff070ff,$ff10e050,$ffffe050,$ff50e8ff,$ffffffff
EndDataSection
;- Structures
Structure RenderLUT
bit_expand.l[256 * 8] ; offset 0
color.l[256 * 2] ; offset 8192
offset.u[768] ; offset 10240
EndStructure
;- Global variables
Global *Mem, *RenderLUT.RenderLUT
;- Init lookup table
Procedure SwapRB(color.l)
!mov eax, [p.v_color]
!bswap eax
!ror eax, 8
ProcedureReturn
EndProcedure
Procedure InitTable()
Protected.i bit, col, i, ink, paper, row
If Not *RenderLUT
*Mem = AllocateMemory(SizeOf(RenderLUT) + 32)
*RenderLUT.RenderLUT = (*Mem + 31) & -32
For i = 0 To 255
If i & $80
ink = (i >> 3 & 15) : paper = (i >> 3 & 8) | (i & 7) ; flash
Else
paper = (i >> 3 & 15) : ink = (i >> 3 & 8) | (i & 7) ; normal
EndIf
CompilerIf #SwapRB
*RenderLUT\color[i << 1 ] = SwapRB(PeekL(?ColorLUT + paper << 2))
*RenderLUT\color[i << 1 + 1] = SwapRB(PeekL(?ColorLUT + ink << 2))
CompilerElse
*RenderLUT\color[i << 1 ] = PeekL(?ColorLUT + paper << 2) ; paper
*RenderLUT\color[i << 1 + 1] = PeekL(?ColorLUT + ink << 2) ; ink
CompilerEndIf
Next
For row = 0 To 7
For col = 0 To 31
*RenderLUT\offset[row << 5 | col] = row << 5 | col
*RenderLUT\offset[row << 5 | col | 256] = row << 5 | col | 2048
*RenderLUT\offset[row << 5 | col | 512] = row << 5 | col | 4096
Next
Next
For i = 0 To 255
For bit = 0 To 7
If i & ($80 >> bit)
*RenderLUT\bit_expand[i << 3 | bit] = -1
EndIf
Next
Next
EndIf
EndProcedure
InitTable()
;- Main code
CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
Macro rax : eax : EndMacro
Macro rbx : ebx : EndMacro
Macro rcx : ecx : EndMacro
Macro rdx : edx : EndMacro
Macro rsi : esi : EndMacro
Macro rdi : edi : EndMacro
Macro rsp : esp : EndMacro
CompilerEndIf
Macro M_8x1(line)
!movzx eax, byte [rsi + rbx + line*256] ; get bits
!shl eax, 5
!movdqa xmm0, [rdx + rax] ; expand every bit to 32 bits
!movdqa xmm1, [rdx+16 + rax] ; expand every bit to 32 bits
!pand xmm0, xmm3
!pand xmm1, xmm3
!pxor xmm0, xmm2
!pxor xmm1, xmm2
CompilerIf #FlipY
!movdqu [rdi + (7-line)*1024], xmm0
!movdqu [rdi+16 + (7-line)*1024], xmm1
CompilerElse
!movdqu [rdi + line*1024], xmm0
!movdqu [rdi+16 + line*1024], xmm1
CompilerEndIf
EndMacro
Procedure RenderSCR(*SCR, *Target, FlashState = 0)
FlashState = (FlashState << 7) ! $7f
; backup registers without push
; so references to local variables stay valid
mov [rsp - 8], rbx
mov [rsp - 16], rsi
mov [rsp - 24], rdi
; load registers
mov rdx, *RenderLUT
mov rsi, *SCR
mov rdi, *Target
CompilerIf #FlipY
add rdi, 188416
CompilerEndIf
; block loop
!xor ecx, ecx ; ecx = counter (0 - 767)
!.block_loop:
movzx eax, byte [rsi+6144 + rcx] ; get attributes of block
!and eax, [p.v_FlashState]
movq xmm0, [rdx+8192 + rax*8]
!pshufd xmm2, xmm0, 00000000b ; paper
!pshufd xmm3, xmm0, 01010101b ; ink
!pxor xmm3, xmm2
movzx ebx, word [rdx+10240 + rcx*2] ; get block offset
M_8x1(0) ; block line 0
M_8x1(1) ; block line 1
M_8x1(2) ; block line 2
M_8x1(3) ; block line 3
M_8x1(4) ; block line 4
M_8x1(5) ; block line 5
M_8x1(6) ; block line 6
M_8x1(7) ; block line 7
add rdi, 32
!inc ecx
!test ecx, 31 ; new row check
!jnz .block_loop
CompilerIf #FlipY
sub rdi, 9216
CompilerElse
add rdi, 7168
CompilerEndIf
!cmp ecx, 768
!jne .block_loop
; restore registers
mov rdi, [rsp - 24]
mov rsi, [rsp - 16]
mov rbx, [rsp - 8]
EndProcedure
EndModule