Created
December 27, 2021 21:20
-
-
Save samneggs/4d228d0bc948a556bb197b60918bf86b to your computer and use it in GitHub Desktop.
Line function in MicroPython Viper and Inline Assembly
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from LCD_3inch5 import LCD_3inch5 | |
import framebuf | |
from math import sin,cos,pi, radians | |
from time import sleep_ms, sleep_us, ticks_diff, ticks_us, sleep | |
from micropython import const | |
from uctypes import addressof | |
import array | |
from usys import exit | |
import gc | |
SCREEN_WIDTH = const(240) | |
SCREEN_HEIGHT = const(240) | |
SPRITE_WIDTH = const(240) | |
SPRITE_HEIGHT = const(240) | |
CTL_X1 = const(0) | |
CTL_Y1 = const(4) | |
CTL_X2 = const(8) | |
CTL_Y2 = const(12) | |
CTL_COLOR = const(16) | |
CTL_WIDTH = const(20) | |
CTL_YLONGER = const(24) | |
CTL_SHORTLEN = const(28) | |
CTL_LONGLEN = const(32) | |
CTL_DECINC = const(36) | |
CTL_8000 = const(40) | |
# control CTL_X1, CTL_X2, CTL_Y1, CTL_Y1, CTL_COLOR, CTL_WIDTH | |
line_ctl=array.array('i',(0,0,0,0,0,240,0,0,0,0,0x8000,0)) | |
@micropython.asm_thumb | |
def line_asm(r0,r1)->int: # r0=screen address,r1 = control | |
mov(r2,0) | |
str(r2, [r1, CTL_YLONGER]) # yLonger=False | |
str(r2, [r1, CTL_DECINC]) # decInc=0 | |
ldr(r2, [r1, CTL_Y2]) # y2 | |
ldr(r3, [r1, CTL_Y1]) # y1 | |
sub(r2,r2,r3) # y2-y1 | |
str(r2, [r1, CTL_SHORTLEN]) # shortLen=y2-y1 | |
ldr(r3, [r1, CTL_X2]) # x2 | |
ldr(r4, [r1, CTL_X1]) # x1 | |
sub(r3,r3,r4) # x2-x1 | |
str(r3, [r1, CTL_LONGLEN]) # longLen=x2-x1 | |
mov(r4,r2) | |
bl(ABSOLUTE) # abs(shortLen) | |
mov(r2,r4) | |
mov(r4,r3) | |
bl(ABSOLUTE) # abs(longLen) | |
mov(r3,r4) | |
cmp(r2,r3) | |
ble(NOSWAP) | |
ldr(r3, [r1, CTL_SHORTLEN]) | |
ldr(r4, [r1, CTL_LONGLEN]) | |
str(r4, [r1, CTL_SHORTLEN]) | |
str(r3, [r1, CTL_LONGLEN]) # swap shortLen and longLen | |
mov(r7,1) | |
str(r7, [r1, CTL_YLONGER]) # yLonger=True | |
label(NOSWAP) | |
ldr(r3, [r1, CTL_LONGLEN]) | |
cmp(r3,0) # if (longLen==0): | |
beq(YLONGER) # | |
ldr(r2, [r1, CTL_SHORTLEN]) # decInc = (shortLen << 16) // longLen | |
push({r0, r1}) | |
lsl(r0,r2,16) # r0 is dividend | |
ldr(r1, [r1, CTL_LONGLEN]) # r1 is divisior | |
# -------------------divide routine----------r0=r0//r1------------- | |
mov(r7,pc) # address of next statement will go in r7 | |
b(SIOSKIP) | |
data(2,0xd000) # SIO_BASE _u(0xd0000000) | |
align(2) | |
label(SIOSKIP) | |
ldrh(r7, [r7, 0]) # read variable | |
lsl(r3,r7,16) | |
add(r3,0x60) # offset so strh will work | |
str(r0, [r3, 8]) # SIO_DIV_SDIVIDEND_OFFSET _u(0x00000068)8 | |
str(r1, [r3, 12]) # SIO_DIV_SDIVISOR_OFFSET _u(0x0000006c)12 | |
nop() | |
nop() | |
nop() | |
nop() | |
nop() | |
nop() | |
nop() | |
nop() | |
nop() | |
ldr(r1, [r3, 20]) #SIO_DIV_REMAINDER_OFFSET _u(0x00000074)20 | |
ldr(r0, [r3, 16]) #SIO_DIV_QUOTIENT_OFFSET _u(0x00000070)16 | |
#----------------end divide------------------------------------- | |
mov(r3,r0) | |
pop({r1, r0}) | |
str(r3, [r1, CTL_DECINC]) # decInc = (shortLen << 16) // longLen | |
label(YLONGER) | |
ldr(r2, [r1, CTL_YLONGER]) | |
cmp(r2,0) # if (yLonger): | |
beq(DO_X1) | |
ldr(r2, [r1, CTL_LONGLEN]) | |
cmp(r2,0) # if (longLen>0): | |
ble(DO_Y1NEG) | |
ldr(r3, [r1, CTL_Y1]) # Y1 | |
add(r2,r2,r3) # longLen += y1 | |
str(r2, [r1, CTL_LONGLEN]) | |
ldr(r3, [r1, CTL_X1]) | |
lsl(r3,r3,16) # x1<<16 | |
ldr(r2, [r1, CTL_8000]) | |
add(r2,r2,r3) # (r2) j=0x8000+(x1<<16) | |
ldr(r5, [r1, CTL_Y1]) # (r5) Y1 | |
ldr(r6, [r1, CTL_LONGLEN]) # (r6) longLen | |
ldr(r3, [r1, CTL_DECINC]) # (r3) decInc | |
label(DO_Y1POS) | |
asr(r4,r2,16) | |
str(r4, [r1, CTL_X2]) # (r4) x2=j>>16 | |
bl(PIXEL_XY) | |
add(r2,r2,r3) # j+=decInc | |
add(r5,r5,1) # y1+=1 | |
cmp(r5,r6) | |
ble(DO_Y1POS) | |
b(EXIT) | |
label(DO_Y1NEG) | |
ldr(r3, [r1, CTL_Y1]) # Y1 | |
add(r2,r2,r3) # longLen += y1 | |
str(r2, [r1, CTL_LONGLEN]) | |
ldr(r3, [r1, CTL_X1]) | |
lsl(r3,r3,16) # x1<<16 | |
ldr(r2, [r1, CTL_8000]) | |
add(r2,r2,r3) # (r2) j=0x8000+(x1<<16) | |
ldr(r5, [r1, CTL_Y1]) # (r5) Y1 | |
ldr(r6, [r1, CTL_LONGLEN]) # (r6) longLen | |
ldr(r3, [r1, CTL_DECINC]) # (r3) decInc | |
label(LOOP_Y1NEG) | |
asr(r4,r2,16) | |
str(r4, [r1, CTL_X2]) # (r4) x2=j>>16 | |
bl(PIXEL_XY) | |
sub(r2,r2,r3) # j-=decInc | |
sub(r5,r5,1) # y1-=1 | |
cmp(r5,r6) | |
bge(LOOP_Y1NEG) | |
b(EXIT) | |
label(DO_X1) | |
ldr(r2, [r1, CTL_LONGLEN]) | |
cmp(r2,0) # if (longLen>0): | |
ble(DO_X1NEG) | |
ldr(r3, [r1, CTL_X1]) # x1 | |
add(r2,r2,r3) # longLen += x1 | |
str(r2, [r1, CTL_LONGLEN]) | |
ldr(r3, [r1, CTL_Y1]) | |
lsl(r3,r3,16) # y1<<16 | |
ldr(r2, [r1, CTL_8000]) | |
add(r2,r2,r3) # (r2) j=0x8000+(y1<<16) | |
ldr(r5, [r1, CTL_X1]) # (r5) x1 | |
ldr(r6, [r1, CTL_LONGLEN]) # (r6) longLen | |
ldr(r3, [r1, CTL_DECINC]) # (r3) decInc | |
label(LOOP_X1POS) | |
asr(r4,r2,16) | |
str(r4, [r1, CTL_Y2]) # (r4) y2=j>>16 | |
bl(PIXEL_YX) | |
add(r2,r2,r3) # j+=decInc | |
add(r5,r5,1) # x1+=1 | |
cmp(r5,r6) | |
ble(LOOP_X1POS) | |
b(EXIT) | |
label(DO_X1NEG) | |
ldr(r3, [r1, CTL_X1]) # x1 | |
add(r2,r2,r3) # longLen += x1 | |
str(r2, [r1, CTL_LONGLEN]) | |
ldr(r3, [r1, CTL_Y1]) | |
lsl(r3,r3,16) # y1<<16 | |
ldr(r2, [r1, CTL_8000]) | |
add(r2,r2,r3) # (r2) j=0x8000+(y1<<16) | |
ldr(r5, [r1, CTL_X1]) # (r5) x1 | |
ldr(r6, [r1, CTL_LONGLEN]) # (r6) longLen | |
ldr(r3, [r1, CTL_DECINC]) # (r3) decInc | |
label(LOOP_X1NEG) | |
asr(r4,r2,16) | |
str(r4, [r1, CTL_Y2]) # (r4) y2=j>>16 | |
bl(PIXEL_YX) | |
sub(r2,r2,r3) # j-=decInc | |
sub(r5,r5,1) # x1-=1 | |
cmp(r5,r6) | |
bge(LOOP_X1NEG) | |
b(EXIT) | |
# subroutines ---------------------------------------------- | |
label(ABSOLUTE) # returns absolute value of r4, uses r7 | |
mov(r7,0) # | |
cmp(r4,r7) # is positive? | |
bgt(POSITIVE) | |
mvn(r7,r4) # abs()-1 | |
add(r7,1) # abs() | |
mov(r4,r7) | |
label(POSITIVE) | |
bx(lr) # return | |
label(PIXEL_XY) # sets pixel in r4(x), r5(y), uses r7 | |
ldr(r7, [r1, CTL_WIDTH]) | |
cmp(r5,r7) | |
mul(r7,r5) # y * width | |
add(r7,r7,r4) # y * width + x | |
add(r7,r7,r7) # double for 2 bytes per pixel | |
add(r7,r7,r0) # dest[y * width + x] | |
ldrh(r4, [r1, CTL_COLOR]) | |
strh(r4, [r7, 0]) | |
label(PIXEL_XY_DONE) | |
bx(lr) # return | |
label(PIXEL_YX) # sets pixel in r5(x), r4(y), uses r7 | |
ldr(r7, [r1, CTL_WIDTH]) | |
mul(r7,r4) # y * width | |
add(r7,r7,r5) # y * width + x | |
add(r7,r7,r7) # double for 2 bytes per pixel | |
add(r7,r7,r0) # dest[y * width + x] | |
ldrh(r4, [r1, CTL_COLOR]) | |
strh(r4, [r7, 0]) | |
bx(lr) # return | |
label(EXIT) # end assembly routine | |
@micropython.asm_thumb | |
def coords_asm(r0,r1,r2)->int: | |
str(r1, [r0, CTL_X2]) | |
str(r2, [r0, CTL_Y2]) | |
# 100 times 0,0,99,99 (x1,y1,x2,y2) | |
# 0.00802 no draw, code only | |
# 0.70477 screen show this def skipped | |
# 0.71721 framebuffer line built-in | |
# 0.72195 direct to framebuffer | |
# 0.90210 s.sprite.pixel 100x100 framebuffer | |
# 10.19292 lcd.draw_point direct to screen | |
# THE EXTREMELY FAST LINE ALGORITHM Variation E (Addition Fixed Point PreCalc) | |
# Copyright 2001-2, By Po-Han Lin | |
@micropython.viper | |
def draw_line( x1:int, y1:int, x2:int, y2:int , color:int): | |
width=240 | |
dest=ptr16(screen) | |
yLonger=False | |
shortLen=y2-y1 | |
longLen=x2-x1 | |
if (abs(shortLen)>abs(longLen)): | |
swap=shortLen | |
shortLen=longLen | |
longLen=swap | |
yLonger=True | |
decInc=0 | |
if (longLen==0): | |
decInc=0 | |
else: | |
decInc = (shortLen << 16) // longLen | |
if (yLonger): | |
if (longLen>0): | |
longLen+=y1 | |
j=0x8000+(x1<<16) | |
while y1<=longLen: | |
x2=j>>16 | |
i = y1 * width + x2 | |
dest[i]=color | |
j+=decInc | |
y1+=1 | |
return | |
longLen+=y1 | |
j=0x8000+(x1<<16) | |
while y1>=longLen: | |
x2=j>>16 | |
i = y1 * width + x2 | |
dest[i]=color | |
j-=decInc | |
y1-=1 | |
return | |
if (longLen>0): | |
longLen+=x1 | |
j=0x8000+(y1<<16) | |
while x1<=longLen: | |
y2=j>>16 | |
i = y2 * width + x1 | |
dest[i]=color | |
j+=decInc | |
x1+=1 | |
return | |
longLen+=x1 | |
j=0x8000+(y1<<16) | |
while x1>=longLen: | |
y2=j>>16 | |
i = y2 * width + x1 | |
dest[i]=color | |
j-=decInc | |
x1-=1 | |
if __name__=='__main__': | |
lcd = LCD_3inch5() | |
lcd.bl_ctrl(50) | |
lcd.Fill(lcd.BLACK) | |
buffer=bytearray(SCREEN_WIDTH*SCREEN_HEIGHT*2) | |
screen=framebuf.FrameBuffer(buffer,SCREEN_WIDTH,SCREEN_HEIGHT,framebuf.RGB565) | |
screen.fill(lcd.BLACK) | |
r=range(50) | |
gticks=ticks_us() | |
line_ctl[0]=120 | |
line_ctl[1]=120 | |
line_ctl[3]=239 | |
line_ctl[4]=lcd.WHITE | |
for x in range(0,240,1): | |
#screen.line(120,120,x,239,lcd.WHITE) | |
#screen.line(120,120,0,x,lcd.WHITE) | |
#screen.line(120,120,x,0,lcd.WHITE) | |
#screen.line(120,120,239,x,lcd.WHITE) # 0.105152 | |
#continue | |
#draw_line(120,120,x,239,lcd.WHITE) | |
#draw_line(120,120,0,x,lcd.WHITE) | |
#draw_line(120,120,x,0,lcd.WHITE) | |
#draw_line(120,120,239,x,lcd.WHITE) # 0.102932 | |
#continue | |
coords_asm(line_ctl,x,239) | |
#line_ctl[2]=x | |
#line_ctl[3]=239 | |
line_asm(screen,line_ctl) | |
#line_ctl[2]=x | |
#line_ctl[3]=0 | |
coords_asm(line_ctl,x,0) | |
line_asm(screen,line_ctl) | |
#line_ctl[2]=239 | |
#line_ctl[3]=x | |
coords_asm(line_ctl,239,x) | |
line_asm(screen,line_ctl) | |
#line_ctl[2]=0 | |
#line_ctl[3]=x | |
coords_asm(line_ctl,0,x) | |
line_asm(screen,line_ctl) # 0.041614 | |
#lcd.show_xy(0,0,0+SCREEN_WIDTH-1,0+SCREEN_HEIGHT-1,screen) | |
delta = ticks_diff(ticks_us(), gticks) | |
lcd.show_xy(0,0,0+SCREEN_WIDTH-1,0+SCREEN_HEIGHT-1,screen) | |
f0=(delta/1000000) | |
print(f0) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment