Skip to content

Instantly share code, notes, and snippets.

@samneggs
Created December 27, 2021 21:20
Show Gist options
  • Save samneggs/4d228d0bc948a556bb197b60918bf86b to your computer and use it in GitHub Desktop.
Save samneggs/4d228d0bc948a556bb197b60918bf86b to your computer and use it in GitHub Desktop.
Line function in MicroPython Viper and Inline Assembly
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