Skip to content

Instantly share code, notes, and snippets.

@samneggs
Created February 11, 2022 05:29
Show Gist options
  • Save samneggs/2eb6fc1c47581c4759841542d8d7aedf to your computer and use it in GitHub Desktop.
Save samneggs/2eb6fc1c47581c4759841542d8d7aedf to your computer and use it in GitHub Desktop.
Doom Fire in Assembly (mostly)
import gc9a01
from machine import Pin, SPI, PWM, WDT
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 math import sin,cos,pi,radians,sqrt,tan
from random import randint
from uctypes import addressof
MAXSCREEN_X = const(240)
MAXSCREEN_Y = const(240)
display_buffer=bytearray(MAXSCREEN_X * MAXSCREEN_Y * 2)
fire_rgb = array.array('H',(8192 ,8216 ,24616 ,24640 ,41040 ,57440 ,57456 ,8329 ,24729 ,57513 ,8378 ,8386 ,24794 ,
41178 ,41178 ,57554 ,57554 ,8659 ,25035 ,41419 ,57803 ,8908 ,8900 ,25284 ,41924 ,58300 ,
58300 ,9405 ,9405 ,26045 ,26037 ,42421 ,42677 ,28110 ,62430 ,30959 ,65535))
#fire_rgb = array.array('H',(8192 ,24616 ,41040 ,57456 ,24729 ,8378 ,24794 ,
## 41178 ,57554 ,25035 ,57803 ,8900 ,41924 ,
# 58300 ,9405 ,26037 ,42677 ,62430 ,65535))
def bl_ctrl(duty):
pwm = PWM(Pin(13))
pwm.freq(1000)
if(duty>=100):
pwm.duty_u16(65535)
else:
pwm.duty_u16(655*duty)
fire_buff=bytearray(MAXSCREEN_X*MAXSCREEN_Y)
@micropython.viper
def drawfire():
texture_addr=ptr16(display_buffer)
fire_addr=ptr8(fire_buff)
rgb_addr=ptr16(fire_rgb)
for x in range(0,MAXSCREEN_X):
fire_addr[(MAXSCREEN_X-1)*MAXSCREEN_X+x]=35
for x in range(0,MAXSCREEN_X):
for y in range(100,MAXSCREEN_X):
f_from = y*MAXSCREEN_X+x
if fire_addr[f_from] == 0:
fire_addr[f_from-MAXSCREEN_X]=0
else:
f_to = f_from - MAXSCREEN_X +1 - int(randint(0,3))
fire_addr[f_to] = fire_addr[f_from]- (int(randint(0,3)) & 1)
texture_addr[y*MAXSCREEN_X+x] = rgb_addr[fire_addr[f_to]]
texture_addr[y*MAXSCREEN_X+x] = rgb_addr[fire_addr[f_to]]
W_TEXTURE = const(4)
W_FIRE = const(8)
W_COLOR = const(12)
W_RANDINT = const(16)
W_MAX_X = const(20)
W_WHITE = const(24)
@micropython.asm_thumb
def fire_asm(r0): # fire_ctl (tex_buff,fire_buff,color_l2)
ldr(r1,[r0,W_MAX_X]) # r1= MAX_X
mov(r4,r1) # =
mul(r4,r4) # = MAX_X*MAX_X
sub(r4,r4,r1) # r4 = (MAX_X-1)*MAX_X
label(BASELINE)
ldr(r2,[r0,W_FIRE]) # r2= fire_buff[] address
mov(r3,35) # color index 35*2
add(r2,r2,r4) #
add(r2,r2,r1)
strb(r3,[r2,0]) # fire_buff[index]=35*2
sub(r1,r1,1) # index-=1
cmp(r1,0)
bge(BASELINE)
mov(r1,0) # r1=x
label(X_LOOP)
mov(r2,100) # r2=y
label(Y_LOOP)
mov(r3,r2) # r3=y
ldr(r4,[r0,W_MAX_X]) # MAX_X
mul(r3,r4) # y*MAX_X
add(r3,r3,r1) # y*MAX_X+x
ldr(r5,[r0,W_FIRE]) # fire_addr[]
add(r3,r3,r5) # r3=fire_addr[f_from] address
ldrb(r4,[r3,0]) # r4=fire_addr[f_from] data
ldr(r5,[r0,W_MAX_X]) # MAX_X
sub(r5,r3,r5) # r5=fire_addr[f_from-MAX_X] address
cmp(r4,0)
bne(NOTZERO)
mov(r6,0)
strb(r6,[r5,0]) # r5=fire_addr[f_from-MAX_X]=0
b(DONE)
label(NOTZERO)
ldr(r6,[r0,W_RANDINT]) # randint(0,3))
ldr(r7,[r6,0]) # reads one random bit
lsl(r7,r7,1)
ldr(r6,[r6,0])
orr(r6,r7)
add(r5,r5,1)
sub(r5,r5,r6)
ldr(r6,[r0,W_RANDINT]) # randint(0,3)) & 1
ldr(r7,[r6,0]) # reads one random bit
lsl(r7,r7,1)
ldr(r6,[r6,0])
orr(r6,r7)
mov(r7,1)
and_(r6,r7) # randint(0,3)) & 1
sub(r4,r4,r6)
strb(r4,[r5,0]) # r5=fire_addr[f_from+MAX_X]=fire_addr[f_from]
add(r4,r4,r4)
ldr(r6,[r0,W_COLOR]) # rgb_addr[] address
add(r6,r6,r4) # rgb_addr[fire_addr[f_to]]
mov(r7,1)
bic(r6,r7)
ldrh(r7,[r6,0]) # r7=rgb_addr[fire_addr[f_to]]
ldr(r6,[r0,W_TEXTURE]) # texture_addr[] address
ldr(r5,[r0,W_MAX_X]) # r5= MAX_X
mul(r5,r2) # = y*MAX_X
add(r5,r5,r1) # = y*MAX_X+x
add(r5,r5,r5) # double for strh
add(r5,r5,r6) # texture_addr[y*MAXSCREEN_X+x]
strh(r7,[r5,0]) # texture_addr[y*MAXSCREEN_X+x] = rgb_addr[fire_addr[f_to]]
label(DONE)
add(r2,r2,1) #
cmp(r2,240)
blt(Y_LOOP) # next y
add(r1,r1,1)
cmp(r1,239)
blt(X_LOOP) # next x
label(EXIT)
if __name__=='__main__':
spi = SPI(1, baudrate=63_000_000, sck=Pin(10), mosi=Pin(11))
tft = gc9a01.GC9A01(
spi,
MAXSCREEN_X,
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)
bl_ctrl(100)
sleep(0.5)
screen=framebuf.FrameBuffer(display_buffer, MAXSCREEN_X , MAXSCREEN_Y, framebuf.RGB565)
gticks=ticks_us()
print(gc.mem_free())
fire_ctl =array.array('I',(0,addressof(screen),addressof( fire_buff),addressof(fire_rgb),0x4006001c,240,0xffff,0))
wdt = WDT(timeout=8300) # Watchdog timer reset
while(1):
gticks=ticks_us()
wdt.feed()
screen.fill_rect(0,0,MAXSCREEN_X-1,MAXSCREEN_Y-1,0) #1480 uS sky
#drawfire() #1150uS
fire_asm(fire_ctl)
tft.blit_buffer(screen, 0, 0, MAXSCREEN_X, MAXSCREEN_Y) # 16600uS 240x200
fps=1_000_000//ticks_diff(ticks_us(), gticks)
#print(fps)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment