Skip to content

Instantly share code, notes, and snippets.

@samneggs
Created May 23, 2022 16:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save samneggs/8780274c94c8ce3e00ef8810b3ee9bc8 to your computer and use it in GitHub Desktop.
Save samneggs/8780274c94c8ce3e00ef8810b3ee9bc8 to your computer and use it in GitHub Desktop.
Falling Sand and Water, single assembly routine for both threads
import gc9a01
from gc9a01 import color565
from machine import Pin, SPI, PWM, WDT, freq
import framebuf
from time import sleep_ms, sleep_us, ticks_diff, ticks_us, sleep
from micropython import const
import array
from usys import exit
import gc
from random import randint
from uctypes import addressof
import _thread
MAXSCREEN_X = const(240)
MAXSCREEN_Y = const(240)
WATER_COLOR = const(0xff00)
SAND_COLOR = const(0x00ff)
FIXED_COLOR = const(0xffff)
RANDOM_ADR = const(0x4006001c)
display_buffer=bytearray(MAXSCREEN_X * MAXSCREEN_Y * 2)
text_buffer=bytearray(8*80*2)
DONE=False
RIGHT=False
def bl_ctrl(duty):
pwm = PWM(Pin(13))
pwm.freq(1000)
if(duty>=100):
pwm.duty_u16(65535)
else:
pwm.duty_u16(655*duty)
# http://www.penguintutor.com/programming/picodisplayanimations
def blit_image_file(filename,width,height): # file width, file height
#print(filename,gc.mem_free())
with open (filename, "rb") as file:
file_position = 0
char_position = 0
current_byte = file.read(4) # header
while file_position < (width * height * 2):
current_byte = file.read(1)
# if eof
if len(current_byte) == 0:
break
# copy to buffer
tex_buff[char_position] = ord(current_byte)
char_position += 1
file_position += 1
file.close()
#screen.blit(texture,50,50)
#tft.blit_buffer(screen, 20, 0, MAXSCREEN_X, MAXSCREEN_Y)
#exit()
def blocks():
for i in range(10):
dx=20
min_y=120
screen.fill_rect(randint(0,220),randint(min_y,220),10,10,0xffff)
x=randint(50,220)
y=randint(min_y,220)
screen.line(x,y,x+dx,y+dx,0xffff)
screen.line(x,y+1,x+dx,y+dx+1,0xffff)
x=randint(50,220)
y=randint(min_y,220)
screen.line(x,y,x-dx,y+dx,0xffff)
screen.line(x,y+1,x-dx,y+dx+1,0xffff)
@micropython.viper
def sand2():
screen_addr=ptr16(display_buffer)
for y in range(220,0,-1):
for x in range(0,240):
source=y*MAXSCREEN_X+x-MAXSCREEN_X
sourcecolor=screen_addr[source]
if sourcecolor == 0xff00 or sourcecolor == 0:
continue
dest=y*MAXSCREEN_X+x
destcolor=screen_addr[dest]
if destcolor == 0:
screen_addr[source] = 0
screen_addr[dest] = sourcecolor
elif screen_addr[source+1+MAXSCREEN_X] == 0:
screen_addr[source] = 0
screen_addr[source+1+MAXSCREEN_X] = sourcecolor
elif screen_addr[source-1+MAXSCREEN_X] == 0:
screen_addr[source] = 0
screen_addr[source-1+MAXSCREEN_X] = sourcecolor
SCREEN_CTL = const(0)
MIN_X_CTL = const(4)
MAX_X_CTL = const(8)
SAND_CTL = const(12)
WATER_CTL = const(16)
FIXED_CTL = const(20)
RANDOM_CTL = const(24)
@micropython.asm_thumb
def sand_asm(r0):
mov(r1,239) # r1 = y
label(LOOP_Y)
mov(r7,255) # stack marker
push({r7})
mov(r7,1)
mov(r2,r1)
and_(r2,r7)
bne(LEFT2RIGHT)
ldr(r2,[r0,MAX_X_CTL]) # max x
b(LOOP_X)
label(LEFT2RIGHT)
ldr(r2,[r0,MIN_X_CTL]) # min x
label(LOOP_X) # r2 = x
mov(r3,240) # 240
mul(r3,r1) # 240*y
add(r3,r3,r2) # 240*y+x
mov(r4,r3)
sub(r4,240) # -XMAX
add(r3,r3,r3) # double ldrh
ldr(r5,[r0,SCREEN_CTL])
add(r3,r3,r5) # r3 = dest addr
add(r4,r4,r4) # double ldrh
add(r4,r4,r5) # r4 = source addr
ldrh(r5,[r4,0]) # r5 = sourcecolor
cmp(r5,0)
beq(NEXT_X) # skip if source=0
ldr(r7,[r0,FIXED_CTL])
cmp(r5,r7)
beq(NEXT_X) # skip if source fixed
ldrh(r6,[r3,0]) # r6=destcolor
cmp(r6,0)
beq(MOVEDOWN) # move down if dest=0
ldr(r7,[r0,WATER_CTL])
cmp(r7,r5)
beq(TRYPLUS1) # try move diag if source=water
cmp(r5,0xff) # 0x00ff=yellow
beq(YELLOW)
b(NEXT_X)
label(YELLOW)
cmp(r6,r7) # is dest water?
bne(TRYPLUS1)
strh(r7,[r4,0]) # source = 0
strh(r5,[r3,0]) # dest = sourcecolor
b(NEXT_X)
label(MOVEDOWN)
mov(r6,0)
strh(r6,[r4,0]) # source = 0
strh(r5,[r3,0]) # dest = sourcecolor
b(NEXT_X)
label(TRYPLUS1)
mov(r3,r4) # source
mov(r6,241) # 1 + MAX_X
add(r6,r6,r6) # double ldrh
add(r3,r3,r6) # source + 1 + MAX_X
ldrh(r6,[r3,0]) # r6=diag color
cmp(r6,0)
beq(DIAGRIGHT) # if dest empty move diag
cmp(r6,r7)
bne(TRYMINUS1) # if dest not water skip
cmp(r5,0xff)
bne(TRYMINUS1) # if source not sand skip
label(DIAGRIGHT) # move diag to right
strh(r6,[r4,0]) # source = 0
strh(r5,[r3,0]) # source + 1 + MAX_X = sourcecolor
b(NEXT_X)
label(TRYMINUS1)
sub(r3,4) # source-1+MAXSCREEN_X
ldrh(r6,[r3,0])
cmp(r6,0)
beq(DIAGLEFT) # if dest empty move diag
cmp(r5,r7)
beq(SAVE_WATER) # if source is water skip
cmp(r6,r7)
beq(DIAGLEFT) # if dest is water move diag
b(SAVE_WATER)
label(DIAGLEFT)
strh(r6,[r4,0]) # source = 0
strh(r5,[r3,0]) # source - 2 + MAX_X = sourcecolor
b(NEXT_X)
label(SAVE_WATER)
cmp(r5,0xff) # is sand?
beq(NEXT_X)
mov(r7,r2)
push({r7})
label(NEXT_X)
mov(r7,1)
mov(r6,r1)
and_(r6,r7)
bne(LEFT2RIGHT1)
sub(r2,1)
ldr(r7,[r0,MIN_X_CTL]) # min x
cmp(r2,r7)
bne(LOOP_X)
b(WATER)
label(LEFT2RIGHT1)
add(r2,1)
ldr(r7,[r0,MAX_X_CTL]) # max x
cmp(r2,r7)
bne(LOOP_X)
label(WATER) #------DO WATER LEFT/RIGHT----------
pop({r7})
cmp(r7,255)
beq(WATER_DONE)
add(r7,1)
mov(r4,r1)
sub(r4,1)
mov(r3,240) # 240
mul(r3,r4) # 240*y
add(r3,r3,r7) # 240*y+x
sub(r3,2) # 240*y+x-2
add(r3,r3,r3) # double ldrh
ldr(r5,[r0,SCREEN_CTL])
add(r3,r3,r5) # r3 = dest addr
ldrh(r5,[r3,2]) # r5 = source color
label(RANDOM)
ldr(r7,[r0,RANDOM_CTL]) # get random addr
ldr(r7,[r7,0]) # get random bit
cmp(r7,1) # choose left/right first
beq(LEFT_FIRST)
b(TEST_RIGHT2)
label(LEFT_FIRST)
b(TEST_LEFT)
label(TEST_LEFT)
ldrh(r4,[r3,0]) # r4 = left dest color
cmp(r4,0)
bne(TEST_RIGHT)
mov(r6,0)
strh(r6,[r3,2])
strh(r5,[r3,0]) # move color to left
b(WATER)
label(TEST_RIGHT)
ldrh(r4,[r3,4]) # r4 = right dest color
cmp(r4,0)
bne(WATER)
mov(r6,0)
strh(r6,[r3,2])
strh(r5,[r3,4]) # move color to right
b(WATER)
label(TEST_RIGHT2)
ldrh(r4,[r3,4]) # r4 = right dest color
cmp(r4,0)
bne(TEST_LEFT2)
mov(r6,0)
strh(r6,[r3,2])
strh(r5,[r3,4]) # move color to right
b(WATER)
label(TEST_LEFT2)
ldrh(r4,[r3,0]) # r4 = left dest color
cmp(r4,0)
bne(WATER)
mov(r6,0)
strh(r6,[r3,2])
strh(r5,[r3,0]) # move color to left
b(WATER)
label(WATER_DONE)
sub(r1,1)
beq(EXIT)
b(LOOP_Y)
label(EXIT)
def core1():
global DONE,screen,RIGHT,control_asm
i=0
while i<240:
i+=1
gticks=ticks_us()
if i==50:
screen.fill_rect(randint(0,220),0,20,20,0xff) #0x7c02)
if i==100:
screen.fill_rect(randint(0,220),0,20,20,0xff00) #0x7c02)
i=0
screen.pixel(randint(0,240),0,0xff00)
screen.pixel(randint(90,95),0,0xff)
RIGHT=True
sand_asm(control_lasm)
#if i==25 or i==50 or i==75 or i==99:
tft.blit_buffer(screen, 0, 0, MAXSCREEN_X, MAXSCREEN_Y)
fps=1_000_000//ticks_diff(ticks_us(), gticks)
print(fps)
DONE=True
@micropython.viper
def resize():
screen_addr=ptr16(display_buffer)
text_addr=ptr16(text_buffer)
offset = 80*MAXSCREEN_X+10
for y in range(8):
for x in range(60):
color=text_addr[y*80+x]
for ly in range(5):
for lx in range(5):
screen_addr[(ly+(5*y))*MAXSCREEN_X+(4*x)+lx+offset]=color
if __name__=='__main__':
spi = SPI(1, baudrate=80_000_000, sck=Pin(10), mosi=Pin(11))
tft = gc9a01.GC9A01(
spi,
240,
240,
reset=Pin(12, Pin.OUT),
cs=Pin(9, Pin.OUT),
dc=Pin(8, Pin.OUT),
backlight=Pin(13, Pin.OUT),
rotation=0)
tft.init()
tft.rotation(0)
tft.fill(gc9a01.BLACK)
tft.inversion_mode(True)
bl_ctrl(100)
sleep(0.5)
screen=framebuf.FrameBuffer(display_buffer, MAXSCREEN_X , MAXSCREEN_Y, framebuf.RGB565)
txt=framebuf.FrameBuffer(text_buffer, 80 , 8, framebuf.RGB565)
control_lasm=array.array('I',(addressof(screen),0,120,SAND_COLOR,WATER_COLOR,FIXED_COLOR,RANDOM_ADR))
control_rasm=array.array('I',(addressof(screen),120,240,SAND_COLOR,WATER_COLOR,FIXED_COLOR,RANDOM_ADR))
txt.text('PI PICO',0,0,0xffff)
resize()
#blit_image_file('floor.bin',32,32*8) # width, height
gticks=ticks_us()
#wdt = WDT(timeout=8300) # Watchdog timer reset
#blocks()
#tft.blit_buffer(screen, 0, 0, MAXSCREEN_X, MAXSCREEN_Y)
screen.fill_rect(0,200,239,239,0xff00)
#screen.line(0,50,240,50,0xffff)
_thread.start_new_thread(core1, ())
while not DONE:
if RIGHT:
RIGHT=False
sand_asm(control_rasm)
exit()
@bhavesh-k
Copy link

Amazing example of MicroPython optimization! Love it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment