Created
February 11, 2022 05:29
-
-
Save samneggs/2eb6fc1c47581c4759841542d8d7aedf to your computer and use it in GitHub Desktop.
Doom Fire in Assembly (mostly)
This file contains 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
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