124 lines
4.2 KiB
Python
124 lines
4.2 KiB
Python
#!/usr/bin/env -S python3 -m dg
|
||
import "/nmigen/cli/main"
|
||
import "/nmigen/sim/pysim/Simulator"
|
||
import "/nmigen_dg/*"
|
||
import "/os/path" qualified
|
||
import "../common/deduce_ports"
|
||
|
||
|
||
RleXorPrevDecoder = subclass Elaboratable where
|
||
__init__ = w h data ~> None where
|
||
@w, @h, @data, @size = w, h, data, w*h
|
||
|
||
@pixel_x = Signal$ range w # pixel being output
|
||
@pixel_y = Signal$ range h # pixel being output
|
||
@pixel_data = Signal! # data of pixel being output
|
||
@pixel_valid = Signal! # wether pixel being output is valid
|
||
|
||
@next = Signal! # pulse this to start decoding next frame
|
||
|
||
elaborate = platform ~> m where with m = Module! =>
|
||
# Default output
|
||
Sync$ @pixel_valid ::= 0
|
||
|
||
# Data to decode
|
||
data_mem = Memory # TODO: use spi flash instead
|
||
width: 8
|
||
depth: (len @data)
|
||
init: (list$ bytearray$ @data)
|
||
rddata = Submodule.rddata$ data_mem.read_port!
|
||
|
||
# RLE decoder state:
|
||
pixel = Signal 1
|
||
pixel_prev = Signal 1
|
||
n_times = Signal 14
|
||
|
||
# XOR Frame buffer
|
||
frame = Memory
|
||
width: 1
|
||
depth: @size
|
||
rdframe = Submodule.rdframe$ frame.read_port!
|
||
wrframe = Submodule.wrframe$ frame.write_port!
|
||
offset = Signal$ range @size
|
||
Comb$ rdframe.addr ::= offset
|
||
Comb$ wrframe.addr ::= offset
|
||
Sync$ wrframe.en ::= 0
|
||
|
||
do_write_pixel = Signal!
|
||
pixel_to_write = Signal!
|
||
Comb$ do_write_pixel ::= 0 # TODO: needed?
|
||
When do_write_pixel $ ->
|
||
Sync$ @pixel_data ::= (rdframe.data ^ pixel_to_write)
|
||
Sync$ wrframe.data ::= (rdframe.data ^ pixel_to_write)
|
||
Sync$ @pixel_valid ::= 1
|
||
Sync$ wrframe.en ::= 1
|
||
|
||
Sync$ offset ::= offset + 1 # needs to start at -1
|
||
|
||
Sync$ @pixel_y ::= @pixel_y + 1
|
||
When (@pixel_y == @h - 1) $ ->
|
||
Sync$ @pixel_y ::= 0
|
||
Sync$ @pixel_x ::= @pixel_x + 1
|
||
|
||
# RLE & XOR Decoder
|
||
FSM
|
||
DECODED ->
|
||
When @next $ ->
|
||
Sync$ offset ::= -1 # max int
|
||
Sync$ @pixel_y ::= -1 # max int
|
||
Sync$ @pixel_x ::= 0
|
||
DECODED |>. READ
|
||
|
||
READ ->
|
||
Sync$ pixel ::= rddata.data !! 7
|
||
Sync$ n_times ::= rddata.data !! slice 0 6 # TODO: proper slicing syntax would be nice
|
||
Sync$ rddata.addr ::= rddata.addr + 1
|
||
When
|
||
rddata.data !! 6 ,-> READ |>. READ_MORE
|
||
otherwise ,-> READ |>. WRITE_PIXELS_BEGIN
|
||
|
||
READ_MORE ->
|
||
Sync$ n_times ::= ((n_times << 8) | rddata.data)
|
||
Sync$ rddata.addr ::= rddata.addr + 1
|
||
READ_MORE |>. WRITE_PIXELS_BEGIN
|
||
|
||
WRITE_PIXELS_BEGIN ->
|
||
is_first = offset == 0
|
||
has_changed = pixel != pixel_prev
|
||
When (~has_changed & ~is_first) $ -> # there was an omitted n_values=1 in between
|
||
Comb$ pixel_to_write ::= ~pixel
|
||
Comb$ do_write_pixel ::= 1
|
||
|
||
|
||
Sync$ pixel_prev ::= pixel
|
||
WRITE_PIXELS_BEGIN |>. WRITE_PIXELS
|
||
|
||
WRITE_PIXELS ->
|
||
Comb$ pixel_to_write ::= pixel
|
||
Comb$ do_write_pixel ::= 1
|
||
|
||
Sync$ n_times ::= n_times - 1
|
||
When (n_times == 1) $ -> When # == 0 next cycle
|
||
offset == @size - 1 ,-> WRITE_PIXELS |>. DECODED
|
||
otherwise ,-> WRITE_PIXELS |>. READ
|
||
|
||
|
||
BadAppleDecoder = -> RleXorPrevDecoder 85 64 bad_apple_data where
|
||
fname = os.path.join
|
||
os.path.dirname __file__
|
||
"data"
|
||
"bad_apple.bin"
|
||
with f = open fname "rb" =>
|
||
bad_apple_data = f.read!
|
||
bad_apple_data = bad_apple_data !! slice 0 ((len bad_apple_data) // 58) # TODO: use full movie when we've moved data to spi flash
|
||
print ((len bad_apple_data) // 58)
|
||
#bad_apple_data = b"0000"
|
||
|
||
|
||
if __name__ == "__main__" =>
|
||
design = RleXorPrevDecoder 85 64 b"1234"
|
||
ports = deduce_ports design
|
||
main design
|
||
name: "bad_apple"
|
||
ports: ports
|