Compare commits

..

10 Commits

28 changed files with 1510 additions and 68 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
build/ build/
.idea/ .idea/
ice/mandelbrot/impl_1/

View File

@ -2,15 +2,18 @@ cmake_minimum_required(VERSION 3.13...3.27)
include(pico_sdk_import.cmake) include(pico_sdk_import.cmake)
project(usb-video C CXX ASM) project(pico-ice-video C CXX ASM)
pico_sdk_init() pico_sdk_init()
add_subdirectory(pico-ice-sdk) add_subdirectory(pico-ice-sdk)
add_executable(usb-video main.cpp usb_descriptors.c) add_executable(pico-ice-video main.cpp usb_descriptors.c)
target_link_libraries(usb-video pico_ice_sdk pico_ice_usb pico_stdio_usb pico_bootsel_via_double_reset)
target_include_directories(usb-video PUBLIC ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_BINARY_DIR})
pico_add_extra_outputs(usb-video) pico_generate_pio_header(pico-ice-video ${CMAKE_CURRENT_LIST_DIR}/fpga.pio)
pico_enable_stdio_usb(usb-video 0)
pico_enable_stdio_uart(usb-video 0) target_link_libraries(pico-ice-video pico_ice_sdk pico_ice_usb pico_stdio_usb pico_bootsel_via_double_reset)
target_include_directories(pico-ice-video PUBLIC ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_BINARY_DIR})
pico_add_extra_outputs(pico-ice-video)
pico_enable_stdio_usb(pico-ice-video 1)
pico_enable_stdio_uart(pico-ice-video 0)

64
README.md Normal file
View File

@ -0,0 +1,64 @@
# Pico Ice Video
This repository displays a video signal from the Pico Ice FPGA on the
desktop computer, over USB, using the USB Video Device Class (UVC).
You can then take screenshots, record the video, or use it as a demo
during a Zoom call.
Here is the [FPGA
interface](https://git.shylie.info/shylie/pico-ice-video/src/branch/main/ice/mandelbrot/source/impl_1/top.sv). There
is a start wire, really that is the vertical sync signal. There are 8
bits of data that get sent to the RP2040. The RP2040 reads the data
using PIO, writes the data to the inactive frame buffer using direct
memory access. Meanwhile the TinyUSB library is writing uncompressed
data to the desktop over USB using the active frame buffer. The
RP2040 sysclk runs at120 MHz, the clkdiv for the pio is 2.5 and the
FPGA runs at 48Mhz. The image size is 320 * 180. The next version of
the Pico-Ice will have the RP2350 Chip which will also support a
higher resolution HDMI output.
This software is based on the [Tiny video USB Capture example](
https://github.com/hathach/tinyusb/tree/master/examples/device/video_capture).
UVC does not need to be fully synchronous: there is no timing to
keep-up with: if you send the frame sometimes slow sometimes fast, it
is fine. In particular if using BULK (throw data in like it's a
truck) endpoint rather than ISOCHRONOUS (always same time
interval...)
## Contact
If you have questions, first please search the Pico Ice discord
server, and then ask. This is a private repository, to make
contributions, please post your branch somewhere and notify the author
@shylie on the Pico Ice Discord server.
## INSTALLATION
To install it on linux , [put the Pico-Ice into install mode](
https://pico-ice.tinyvision.ai/md_programming_the_mcu.html )
Using the command
picocom) --baud 1200 /dev/ttyACM0
Then drag the executable onto the RP2040 drive on the desktop.
## TO DO
**Implement compression**. There are lower complexity compression
techniques,PEG-XS seems to be one of the newer standards thats meant
for low latency and reasonable compression. This may be doable with
the RPi in FW. Doubt MJPG is possible for larger frames as that
requires multiple frames to be in memory.
**Free UP SPI and UART pins** The interface requires 9 pins. There
are 8 RP2040<->FPGA pins, so one of the spi pins is also used. One
could solder a pin between the FPGA and RP2040 and preserve the SPI
bus. Better yet, solder 3 pins and preserve both the SPI bus, and
the default part.
## Special Thanks
Christopher Lozinski (@clozinski) - wrote this README file. Thank you!
josuah (@josuah.demangeon) - helped answer questions during the development of this project
venkat_tv (@venkat_tv) - developed the pico-ice hardware

102
fpga.pio Normal file
View File

@ -0,0 +1,102 @@
.pio_version 0
; green
.define public DIR_PIN 12
; red
.define public REQ_PIN 13
; blue
.define public FIN_PIN 15
.define public CLK_PIN 24
.program fpga
start:
set x, 0
mov x, ~x
mov osr, x ; set pins to out
out pindirs, 8 ; ...
set pindirs, 0b11 ; ...
set pins, 0b01 ; set dir to 1 and req to 0
irq wait 0 ; wait for system to be ready
wait 1 gpio CLK_PIN
wait 0 gpio CLK_PIN
set pins, 0b11 ; set dir and req to 1
send_data_loop:
set x, 0 ; set x to 0
mov x, ~x
pull noblock ; get data from memory
mov x, ~osr
jmp !x recv_data_start ; check for end of values
mov osr, ~x
wait 0 gpio CLK_PIN ; synchronize
wait 1 gpio CLK_PIN ; synchronize
out pins, 8 ; output data to pins
jmp send_data_loop ; keep sending since no null-terminator
recv_data_start:
set pins, 0b00 ; set dir and req to 0
set x, 0 ; reset x to 0
mov osr, x ; set pins to in
out pindirs, 8 ; ...
set pindirs, 0b01 ; ...
wait 1 gpio REQ_PIN ; wait for data to be ready, indicated by req signal high
wait 1 gpio CLK_PIN
.wrap_target
wait 0 gpio CLK_PIN ; synchronize
jmp pin start ; stop receiving data if FPGA is done
wait 1 gpio CLK_PIN ; synchronize
in pins, 8 ; read data from pins
push noblock ; ...
.wrap ; otherwise keep receiving data
% c-sdk {
#include <hardware/dma.h>
static int command_dma_channel;
static int frame_dma_channel;
static void fpga_program_init(PIO pio, uint sm, uint offset, uint bus_base, uint status_base, uint fin_pin)
{
{
pio_sm_config c = fpga_program_get_default_config(offset);
sm_config_set_in_pins(&c, bus_base);
sm_config_set_out_pins(&c, bus_base, 8);
sm_config_set_set_pins(&c, status_base, 2);
sm_config_set_jmp_pin(&c, fin_pin);
sm_config_set_in_shift(&c, false, false, 8);
sm_config_set_out_shift(&c, false, false, 8);
pio_sm_init(pio, sm, offset, &c);
for (int i = 0; i < 8; i++) { pio_gpio_init(pio, bus_base + i); }
for (int i = 0; i < 2; i++) { pio_gpio_init(pio, status_base + i); }
}
command_dma_channel = dma_claim_unused_channel(true);
frame_dma_channel = dma_claim_unused_channel(true);
{
dma_channel_config c = dma_channel_get_default_config(command_dma_channel);
channel_config_set_read_increment(&c, true);
channel_config_set_write_increment(&c, false);
channel_config_set_transfer_data_size(&c, DMA_SIZE_8);
channel_config_set_dreq(&c, pio_get_dreq(pio, sm, true));
channel_config_set_chain_to(&c, frame_dma_channel);
dma_channel_configure(command_dma_channel, &c, &pio->txf[sm], NULL, 0, false);
}
{
dma_channel_config c = dma_channel_get_default_config(frame_dma_channel);
channel_config_set_read_increment(&c, false);
channel_config_set_write_increment(&c, true);
channel_config_set_transfer_data_size(&c, DMA_SIZE_8);
channel_config_set_dreq(&c, pio_get_dreq(pio, sm, false));
dma_channel_configure(frame_dma_channel, &c, NULL, &pio->rxf[sm], FRAME_WIDTH * FRAME_HEIGHT * 2, false);
}
}
%}

13
ice/constraints.pdc Normal file
View File

@ -0,0 +1,13 @@
ldc_set_location -site 35 [get_ports {clk}]
ldc_set_location -site 41 [get_ports {req}]
ldc_set_location -site 40 [get_ports {fin}]
ldc_set_location -site 39 [get_ports {dir}]
ldc_set_location -site 27 [get_ports {data[0]}]
ldc_set_location -site 25 [get_ports {data[1]}]
ldc_set_location -site 21 [get_ports {data[2]}]
ldc_set_location -site 19 [get_ports {data[3]}]
ldc_set_location -site 26 [get_ports {data[4]}]
ldc_set_location -site 23 [get_ports {data[5]}]
ldc_set_location -site 20 [get_ports {data[6]}]
ldc_set_location -site 18 [get_ports {data[7]}]

1
ice/constraints.sdc Normal file
View File

@ -0,0 +1 @@
create_clock -period 83.33333 [get_ports {clk}]

43
ice/coords.sv Normal file
View File

@ -0,0 +1,43 @@
module coords
#(
parameter WIDTH = 256,
parameter HEIGHT = 256,
parameter POS_COUNT = 4,
localparam WIDTH_BITS = $clog2(WIDTH),
localparam HEIGHT_BITS = $clog2(HEIGHT)
)(
input wire clk,
input wire rst,
input wire inc,
output reg [WIDTH_BITS-1:0] x[POS_COUNT],
output reg [HEIGHT_BITS-1:0] y[POS_COUNT],
output wire finished
);
reg [POS_COUNT-1:0] finished_r;
always_ff @(posedge clk) begin
if (rst) begin
integer i;
for (i = 0; i < POS_COUNT; i = i + 1) begin
x[i] <= WIDTH_BITS'(i);
y[i] <= 0;
end
finished_r <= '1;
end else if (inc) begin
integer i;
for (i = 0; i < POS_COUNT; i = i + 1) begin
x[i] <= x[i] + POS_COUNT;
if (32'(x[i]) > (32'(x[i]) + POS_COUNT) % WIDTH) begin
y[i] <= y[i] + 1;
if (32'(y[i]) > (32'(y[i]) + 1) % HEIGHT) begin
finished_r[i] <= 0;
end
end
end
end
end
assign finished = finished_r == 0;
endmodule

View File

@ -0,0 +1,8 @@
[Runmanager]
Geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\0\0\0\0\0\x14\0\0\x1\xca\0\0\0\xb9\0\0\0\0\0\0\0\x14\0\0\x1\xca\0\0\0\xb9\0\0\0\0\0\0\0\0\n\0\0\0\0\0\0\0\0\x14\0\0\x1\xca\0\0\0\xb9)
headerState=@ByteArray(\0\0\0\xff\0\0\0\0\0\0\0\x1\0\0\0\x1\0\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\x15\0\xf0\x1f\0\0\0\t\0\0\0\x11\0\0\0\x64\0\0\0\xe\0\0\0\x64\0\0\0\xf\0\0\0\x64\0\0\0\f\0\0\0\x64\0\0\0\r\0\0\0\x64\0\0\0\x14\0\0\0\x64\0\0\0\x12\0\0\0\x64\0\0\0\x13\0\0\0\x64\0\0\0\x10\0\0\0\x64\0\0\x5\xf\0\0\0\x15\x1\x1\0\x1\0\0\0\0\0\0\0\0\0\0\0\0\x64\xff\xff\xff\xff\0\0\0\x84\0\0\0\0\0\0\0\x15\0\0\0\xc3\0\0\0\x1\0\0\0\0\0\0\0\x64\0\0\0\x1\0\0\0\0\0\0\0\x64\0\0\0\x1\0\0\0\0\0\0\0\x64\0\0\0\x1\0\0\0\0\0\0\0\x64\0\0\0\x1\0\0\0\0\0\0\0\x64\0\0\0\x1\0\0\0\0\0\0\0\x64\0\0\0\x1\0\0\0\0\0\0\0\x64\0\0\0\x1\0\0\0\0\0\0\0\x64\0\0\0\x1\0\0\0\0\0\0\0\x64\0\0\0\x1\0\0\0\0\0\0\0\x64\0\0\0\x1\0\0\0\0\0\0\0\x64\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\x3\xe8\0\0\0\0\x64)
[impl_1%3CStrategy1%3E]
isChecked=false
isHidden=false
isExpanded=false

View File

@ -0,0 +1,7 @@
[General]
IdFilter=@Invalid()
ProcessFilter=@Invalid()
TypeFilter=0
[Individuals]
size=0

3
ice/mandelbrot/drc.log Normal file
View File

@ -0,0 +1,3 @@
DRC: Design Rule Check Radiant Software (64-bit) 2024.1.0.34.2
Sat Sep 28 23:33:51 2024

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<RadiantProject version="4.2" radiant="2024.1.0.34.2" title="mandelbrot" device="iCE40UP5K-SG48I" performance_grade="High-Performance_1.2V" family_int="ice40tp" device_int="itpa08" package_int="SG48" operation_int="IND" speed_int="6" default_implementation="impl_1">
<Options/>
<Implementation title="impl_1" dir="impl_1" description="impl_1" synthesis="synplify" default_strategy="Strategy1">
<Options def_top="top" top="top"/>
<Source name="source/impl_1/top.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog" top_module="top"/>
</Source>
<Source name="../ram.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
<Source name="../coords.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
<Source name="source/impl_1/renderer.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
<Source name="source/impl_1/multiplier.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
<Source name="../spram.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
<Source name="../spram_big.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
<Source name="../constraints.pdc" type="Physical Constraints File" type_short="PDC">
<Options/>
</Source>
<Source name="../constraints.sdc" type="Pre-Synthesis Constraints File" type_short="SDC">
<Options/>
</Source>
</Implementation>
<Strategy name="Strategy1" file="mandelbrot1.sty"/>
</RadiantProject>

View File

@ -0,0 +1,138 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE strategy>
<Strategy version="1.0" predefined="0" description="" label="Strategy1">
<Property name="PROP_BD_EdfHardtimer" value="Enable" time="0"/>
<Property name="PROP_BD_EdfInBusNameConv" value="None" time="0"/>
<Property name="PROP_BD_EdfInLibPath" value="" time="0"/>
<Property name="PROP_BD_EdfInRemLoc" value="Off" time="0"/>
<Property name="PROP_BD_EdfMemPath" value="" time="0"/>
<Property name="PROP_BD_ParSearchPath" value="" time="0"/>
<Property name="PROP_BIT_CmdLineArgs" value="" time="0"/>
<Property name="PROP_BIT_INITEBR0" value="True" time="0"/>
<Property name="PROP_BIT_INITEBR1" value="True" time="0"/>
<Property name="PROP_BIT_INITEBR2" value="True" time="0"/>
<Property name="PROP_BIT_INITEBR3" value="True" time="0"/>
<Property name="PROP_BIT_NVCMSecurity" value="False" time="0"/>
<Property name="PROP_BIT_NoHeader" value="False" time="0"/>
<Property name="PROP_BIT_NoPullup" value="False" time="0"/>
<Property name="PROP_BIT_OSCFREQ" value="Slow" time="0"/>
<Property name="PROP_BIT_OutFormatBitGen" value="bin" time="0"/>
<Property name="PROP_BIT_RunDRCBitGen" value="True" time="0"/>
<Property name="PROP_BIT_SPILowPower" value="False" time="0"/>
<Property name="PROP_BIT_WarmBoot" value="False" time="0"/>
<Property name="PROP_CPE_IPDebugMode" value="False" time="0"/>
<Property name="PROP_IOTIMING_AllSpeed" value="False" time="0"/>
<Property name="PROP_LST_AllowDUPMod" value="False" time="0"/>
<Property name="PROP_LST_AllowMixedAssignments" value="False" time="0"/>
<Property name="PROP_LST_CarryChain" value="True" time="0"/>
<Property name="PROP_LST_CarryChainLength" value="0" time="0"/>
<Property name="PROP_LST_CmdLineArgs" value="" time="0"/>
<Property name="PROP_LST_DSPStyle" value="DSP" time="0"/>
<Property name="PROP_LST_DSPUtil" value="100" time="0"/>
<Property name="PROP_LST_DecodeUnreachableStates" value="False" time="0"/>
<Property name="PROP_LST_EBRUtil" value="100" time="0"/>
<Property name="PROP_LST_EdfFrequency" value="200" time="0"/>
<Property name="PROP_LST_EdfInLibPath" value="" time="0"/>
<Property name="PROP_LST_EdfInRemLoc" value="Off" time="0"/>
<Property name="PROP_LST_EdfMemPath" value="" time="0"/>
<Property name="PROP_LST_FIXGATEDCLKS" value="True" time="0"/>
<Property name="PROP_LST_FSMEncodeStyle" value="Auto" time="0"/>
<Property name="PROP_LST_IOInsertion" value="True" time="0"/>
<Property name="PROP_LST_IgnoreSDCError" value="False" time="0"/>
<Property name="PROP_LST_InterFileDump" value="False" time="0"/>
<Property name="PROP_LST_LoopLimit" value="1950" time="0"/>
<Property name="PROP_LST_MaxFanout" value="1000" time="0"/>
<Property name="PROP_LST_OptimizeGoal" value="Area" time="0"/>
<Property name="PROP_LST_PropagatConst" value="True" time="0"/>
<Property name="PROP_LST_RAMStyle" value="Auto" time="0"/>
<Property name="PROP_LST_ROMStyle" value="Auto" time="0"/>
<Property name="PROP_LST_RWCheckOnRam" value="False" time="0"/>
<Property name="PROP_LST_RemoveDupRegs" value="True" time="0"/>
<Property name="PROP_LST_ReportTrimmedUserNets" value="False" time="0"/>
<Property name="PROP_LST_ResolvedMixedDrivers" value="False" time="0"/>
<Property name="PROP_LST_ResourceShare" value="True" time="0"/>
<Property name="PROP_LST_UseIOReg" value="Auto" time="0"/>
<Property name="PROP_LST_VHDL2008" value="False" time="0"/>
<Property name="PROP_MAPSTA_AnalysisOption" value="Standard Setup and Hold Analysis" time="0"/>
<Property name="PROP_MAPSTA_CmdLineArgs" value="" time="0"/>
<Property name="PROP_MAPSTA_EndPtNumber" value="10" time="0"/>
<Property name="PROP_MAPSTA_NPerEnd" value="1" time="0"/>
<Property name="PROP_MAPSTA_NumPathsPerClock" value="10" time="0"/>
<Property name="PROP_MAPSTA_ReportFormat" value="Lattice Standard" time="0"/>
<Property name="PROP_MAPSTA_SpeedForHoldAnalysis" value="m" time="0"/>
<Property name="PROP_MAPSTA_SpeedForSetupAnalysis" value="default" time="0"/>
<Property name="PROP_MAPSTA_UnconstrainedPathsNumber" value="10" time="0"/>
<Property name="PROP_MAP_IgnoreSDCErr" value="False" time="0"/>
<Property name="PROP_MAP_MapModArgs" value="" time="0"/>
<Property name="PROP_MAP_SigCrossRef" value="False" time="0"/>
<Property name="PROP_MAP_SymCrossRef" value="False" time="0"/>
<Property name="PROP_PARSTA_AnalysisOption" value="Standard Setup and Hold Analysis" time="0"/>
<Property name="PROP_PARSTA_CmdLineArgs" value="" time="0"/>
<Property name="PROP_PARSTA_EndPtNumber" value="10" time="0"/>
<Property name="PROP_PARSTA_NPerEnd" value="1" time="0"/>
<Property name="PROP_PARSTA_NumPathsPerClock" value="10" time="0"/>
<Property name="PROP_PARSTA_ReportFormat" value="Lattice Standard" time="0"/>
<Property name="PROP_PARSTA_SpeedForHoldAnalysis" value="m" time="0"/>
<Property name="PROP_PARSTA_SpeedForSetupAnalysis" value="default" time="0"/>
<Property name="PROP_PARSTA_UnconstrainedPathsNumber" value="10" time="0"/>
<Property name="PROP_PAR_DisableAutoHldTiming" value="False" time="0"/>
<Property name="PROP_PAR_DisableTDParDes" value="False" time="0"/>
<Property name="PROP_PAR_ImposeHoldTimeCorrect" value="False" time="0"/>
<Property name="PROP_PAR_NumOfHostMachineCores" value="1" time="0"/>
<Property name="PROP_PAR_PARModArgs" value="" time="0"/>
<Property name="PROP_PAR_PackLogicUtil" value="" time="0"/>
<Property name="PROP_PAR_ParMultiNodeList" value="" time="0"/>
<Property name="PROP_PAR_ParRunPlaceOnly" value="False" time="0"/>
<Property name="PROP_PAR_PlcIterParDes" value="1" time="0"/>
<Property name="PROP_PAR_PlcStCostTblParDes" value="1" time="0"/>
<Property name="PROP_PAR_PriHldCorrectOverSetup" value="False" time="0"/>
<Property name="PROP_PAR_SaveBestRsltParDes" value="1" time="0"/>
<Property name="PROP_PAR_SpdGradeHoldOpt" value="m" time="0"/>
<Property name="PROP_PAR_SpdGradeSetupOpt" value="Default" time="0"/>
<Property name="PROP_PAR_StopZero" value="False" time="0"/>
<Property name="PROP_PAR_parPathBased" value="On" time="0"/>
<Property name="PROP_POSTSYN_CmdLineArgs" value="" time="0"/>
<Property name="PROP_POSTSYN_ExtModuleFiles" value="" time="0"/>
<Property name="PROP_POSTSYN_IgnoreSDCErr" value="False" time="0"/>
<Property name="PROP_SYNSTA_AnalysisOption" value="Standard Setup and Hold Analysis" time="0"/>
<Property name="PROP_SYNSTA_CmdLineArgs" value="" time="0"/>
<Property name="PROP_SYNSTA_EndPtNumber" value="10" time="0"/>
<Property name="PROP_SYNSTA_NPerEnd" value="1" time="0"/>
<Property name="PROP_SYNSTA_NumPathsPerClock" value="10" time="0"/>
<Property name="PROP_SYNSTA_ReportFormat" value="Lattice Standard" time="0"/>
<Property name="PROP_SYNSTA_UnconstrainedPathsNumber" value="10" time="0"/>
<Property name="PROP_SYN_ClockConversion" value="False" time="0"/>
<Property name="PROP_SYN_CmdLineArgs" value="" time="0"/>
<Property name="PROP_SYN_EdfAllowDUPMod" value="False" time="0"/>
<Property name="PROP_SYN_EdfArea" value="False" time="0"/>
<Property name="PROP_SYN_EdfArrangeVHDLFiles" value="True" time="0"/>
<Property name="PROP_SYN_EdfDefEnumEncode" value="Default" time="0"/>
<Property name="PROP_SYN_EdfFanout" value="1000" time="0"/>
<Property name="PROP_SYN_EdfFrequency" value="200" time="0"/>
<Property name="PROP_SYN_EdfInsertIO" value="False" time="0"/>
<Property name="PROP_SYN_EdfNumCritPath" value="" time="0"/>
<Property name="PROP_SYN_EdfNumStartEnd" value="" time="0"/>
<Property name="PROP_SYN_EdfOutNetForm" value="None" time="0"/>
<Property name="PROP_SYN_EdfPushTirstates" value="True" time="0"/>
<Property name="PROP_SYN_EdfResSharing" value="True" time="0"/>
<Property name="PROP_SYN_EdfRunRetiming" value="Pipelining Only" time="0"/>
<Property name="PROP_SYN_EdfSymFSM" value="True" time="0"/>
<Property name="PROP_SYN_EdfUnconsClk" value="False" time="0"/>
<Property name="PROP_SYN_ExportSetting" value="Yes" time="0"/>
<Property name="PROP_SYN_FDCFiles" value="" time="0"/>
<Property name="PROP_SYN_LibPath" value="" time="0"/>
<Property name="PROP_SYN_RamRWCheck" value="False" time="0"/>
<Property name="PROP_SYN_ResolvedMixedDrivers" value="False" time="0"/>
<Property name="PROP_SYN_ResynthesizeAll" value="True" time="0"/>
<Property name="PROP_SYN_UpdateCompilePtTimData" value="False" time="0"/>
<Property name="PROP_SYN_VHDL2008" value="False" time="0"/>
<Property name="PROP_TIM_MaxDelSimDes" value="" time="0"/>
<Property name="PROP_TIM_MinSpeedGrade" value="False" time="0"/>
<Property name="PROP_TIM_ModPreSimDes" value="" time="0"/>
<Property name="PROP_TIM_NegStupHldTim" value="True" time="0"/>
<Property name="PROP_TIM_TimSimGenPUR" value="True" time="0"/>
<Property name="PROP_TIM_TimSimGenX" value="False" time="0"/>
<Property name="PROP_TIM_TimSimHierSep" value="" time="0"/>
<Property name="PROP_TIM_TrgtSpeedGrade" value="High-Performance_1.2V" time="0"/>
<Property name="PROP_TMCHK_EnableCheck" value="True" time="0"/>
</Strategy>

View File

@ -0,0 +1,369 @@
<HTML>
<HEAD>
<TITLE>Lattice TCL Log</TITLE>
<link href="file:///C:/lscc/radiant/2024.1/data/theme/css/light/report.css" rel="stylesheet" type="text/css" media="screen"/>
<link href="file:///C:/lscc/radiant/2024.1/data/theme/css/print/report.css" rel="stylesheet" type="text/css" media="print"/>
<style type="text/css">
#toc {
position: fixed;
right: 2px;
top: 2px;
padding: 2px 5px 2px 5px;
background-color:rgba(210,210,210,0.1);
border-style: solid;
border-color: rgba(192,192,192,0.8);
border-width:1px;
}
#toc_list {
display: none;
}
</style>
<script type="text/javascript">
<!--
function showTocList() {
var a = document.getElementById("toc_list");
a.style.display = "block";
}
function hideTocList() {
var a = document.getElementById("toc_list");
if (a)
a.style.display = "none";
}
//-->
</script>
</HEAD>
<BODY>
<DIV id="content" onclick="hideTocList()"><PRE>
<A name="pn240928081403"></A><B><U><big>pn240928081403</big></U></B>
#Start recording tcl command: 9/25/2024 13:09:03
#Project Location: C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/mandelbrot; Project name: mandelbrot
prj_create -name "mandelbrot" -impl "impl_1" -dev iCE40UP5K-UWG30ITR -performance "High-Performance_1.2V" -synthesis "synplify"
prj_add_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/top.sv" "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/constraints.sdc" "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/constraints.pdc"
prj_save
prj_remove_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/top.sv"
prj_add_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/top.sv"
prj_remove_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/top.sv"
prj_add_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/mandelbrot/impl_1/top.sv"
prj_remove_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/mandelbrot/impl_1/top.sv"
prj_add_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/mandelbrot/source/impl_1/top.sv"
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_set_device -part iCE40UP5K-SG48I -performance "High-Performance_1.2V"
prj_run Synthesis -impl impl_1
prj_run Map -impl impl_1
prj_run Map -impl impl_1
prj_run Export -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_add_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/spi.sv"
prj_remove_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/spi.sv"
prj_add_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/top.sv"
prj_remove_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/top.sv"
prj_add_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/spi.sv"
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run PAR -impl impl_1
prj_run PAR -impl impl_1
prj_run PAR -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_add_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/xd.sv"
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_remove_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/xd.sv"
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_remove_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/spi.sv"
prj_add_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/spi.sv"
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run Export -impl impl_1
prj_add_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/ram.sv"
prj_disable_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/ram.sv"
prj_enable_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/ram.sv"
prj_remove_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/ram.sv"
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_remove_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/spi.sv"
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
#Stop recording: 9/28/2024 08:14:03
<A name="pn241002102238"></A><B><U><big>pn241002102238</big></U></B>
#Start recording tcl command: 10/2/2024 09:00:03
#Project Location: C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/mandelbrot; Project name: mandelbrot
prj_open "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/mandelbrot/mandelbrot.rdf"
prj_add_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/ram.sv"
#Stop recording: 10/2/2024 10:22:38
<A name="pn241003133906"></A><B><U><big>pn241003133906</big></U></B>
#Start recording tcl command: 10/2/2024 11:19:00
#Project Location: C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/mandelbrot; Project name: mandelbrot
prj_open "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/mandelbrot/mandelbrot.rdf"
prj_run Synthesis -impl impl_1
prj_run Synthesis -impl impl_1
prj_run PAR -impl impl_1
prj_run Synthesis -impl impl_1
prj_run Synthesis -impl impl_1
prj_run Synthesis -impl impl_1
prj_run Synthesis -impl impl_1
prj_run Synthesis -impl impl_1
prj_run Map -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_add_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/color_converter.sv"
prj_remove_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/color_converter.sv"
prj_add_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/framebuffer.sv"
prj_run PAR -impl impl_1
prj_run Synthesis -impl impl_1
prj_run Synthesis -impl impl_1
prj_run Synthesis -impl impl_1
prj_run Synthesis -impl impl_1
prj_run Synthesis -impl impl_1
prj_run Synthesis -impl impl_1
prj_run Synthesis -impl impl_1
prj_run Map -impl impl_1
prj_run Synthesis -impl impl_1
prj_run Synthesis -impl impl_1
prj_run Synthesis -impl impl_1
prj_run Synthesis -impl impl_1
prj_run Synthesis -impl impl_1
prj_run Synthesis -impl impl_1
prj_run Synthesis -impl impl_1
prj_run Synthesis -impl impl_1
prj_run Synthesis -impl impl_1
prj_run Synthesis -impl impl_1
prj_run Synthesis -impl impl_1
prj_run Synthesis -impl impl_1
prj_run Synthesis -impl impl_1
prj_run Export -impl impl_1
prj_run Synthesis -impl impl_1
#Stop recording: 10/3/2024 13:39:06
<A name="pn241004114221"></A><B><U><big>pn241004114221</big></U></B>
#Start recording tcl command: 10/3/2024 13:54:22
#Project Location: C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/mandelbrot; Project name: mandelbrot
prj_open "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/mandelbrot/mandelbrot.rdf"
prj_add_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/fifo.sv"
prj_remove_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/fifo.sv"
prj_add_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/xd.sv"
prj_run Synthesis -impl impl_1
prj_run Synthesis -impl impl_1
prj_run Map -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run Synthesis -impl impl_1
prj_run Export -impl impl_1
prj_set_impl_opt -impl "impl_1" "top" "top"
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_remove_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/xd.sv"
prj_remove_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/framebuffer.sv"
prj_add_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/fifo.sv"
#Stop recording: 10/4/2024 11:42:21
<A name="pn241004151504"></A><B><U><big>pn241004151504</big></U></B>
#Start recording tcl command: 10/4/2024 13:54:24
#Project Location: C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/mandelbrot; Project name: mandelbrot
prj_open "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/mandelbrot/mandelbrot.rdf"
prj_remove_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/fifo.sv"
prj_run Synthesis -impl impl_1
prj_add_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/coords.sv"
prj_add_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/mandelbrot/source/impl_1/renderer.sv"
prj_add_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/mandelbrot/source/impl_1/multiplier.sv"
#Stop recording: 10/4/2024 15:15:04
<A name="pn241008133909"></A><B><U><big>pn241008133909</big></U></B>
#Start recording tcl command: 10/7/2024 10:43:02
#Project Location: C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/mandelbrot; Project name: mandelbrot
prj_open "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/mandelbrot/mandelbrot.rdf"
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
#Stop recording: 10/8/2024 13:39:09
</PRE></DIV>
<DIV id="toc" class="radiant"><span onmousemove="showTocList()">Contents</span>
<UL id="toc_list">
<LI><A href=#pn240928081403>pn240928081403</A></LI>
<LI><A href=#pn241002102238>pn241002102238</A></LI>
<LI><A href=#pn241003133906>pn241003133906</A></LI>
<LI><A href=#pn241004114221>pn241004114221</A></LI>
<LI><A href=#pn241004151504>pn241004151504</A></LI>
<LI><A href=#pn241008133909>pn241008133909</A></LI>
</UL>
</DIV>
<button id="back_to_top" class="radiant" onclick="scrollToTop()">&lt;</button>
<script type="text/javascript">
<!--
var scrollStep = 0;
function scrollToTop(){
var funScroll = function() {
var top = document.body.scrollTop;
if (top == 0) {
scrollStep = 0;
return;
}
if (scrollStep == 0)
scrollStep = top/20 + 1;
top -= scrollStep;
if (top < 0)
top = 0;
document.body.scrollTop = top;
requestAnimationFrame(funScroll);
};
funScroll();
}
window.addEventListener('scroll', function(e) {
var backToTop = document.getElementById('back_to_top')
if (document.body.scrollTop > 0) {
backToTop.style.display = 'block';
} else { backToTop.style.display = 'none' }});
//-->
</script>
<style type="text/css">
#back_to_top {
bottom:20px; right:20px;
width:30px; height:30px;
font-size: 20px;
padding: 2px 5px 2px 5px;
position:fixed;
background-color:rgba(210,210,210,0.1);
border-style: solid;
border-color: rgba(192,192,192,0.8);
border-width:1px;
display:none;
-webkit-transform: rotate(90deg);
-webkit-transform-origin:50% 50%;
}
#back_to_top:focus {
outline-width:0px;
}
</style>
</BODY>

View File

@ -0,0 +1,112 @@
#Start recording tcl command: 10/16/2024 11:13:38
#Project Location: C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/mandelbrot; Project name: mandelbrot
prj_open "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/mandelbrot/mandelbrot.rdf"
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run Export -impl impl_1
prj_run Synthesis -impl impl_1 -forceAll
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run Map -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_remove_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/xd.sv"
prj_run PAR -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run Synthesis -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run PAR -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run Synthesis -impl impl_1
prj_run Synthesis -impl impl_1
prj_run Synthesis -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Synthesis -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_add_source "C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/spram_big.sv"
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run Synthesis -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
prj_run PAR -impl impl_1
prj_run Export -impl impl_1
#Stop recording: 10/17/2024 11:16:18

View File

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<userSetting name="C:/Users/fuzzc/Documents/Hardware/pico-ice/pico-ice-video/ice/mandelbrot/promote.xml" version="Diamond (64-bit) 2024.1.0.34.2" date="Thu Oct 17 11:04:30 2024" vendor="Lattice Semiconductor Corporation" >
<msg mid="35921504" type="Info" internal="true" />
<msg mid="35901328" type="Info" internal="true" />
<msg mid="35901209" type="Warning" internal="true" />
<msg mid="35931002" type="Warning" internal="true" />
</userSetting>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Report>
<ReportView version="2.0">
<Implement name="impl_1">
<ToolReport id="toolpio" path="" status="0"/>
<ToolReport id="toolsso" path="" status="0"/>
</Implement>
</ReportView>

View File

@ -0,0 +1 @@
obj_dir/

View File

@ -0,0 +1,18 @@
VFLAGS = -O3 -x-assign fasta --x-initial fast --noassert
SDL_CFLAGS = `sdl2-config --cflags`
SDL_LDFLAGS = `sdl2-config --libs`
run: build
cd obj_dir && ./Vtop
wave: run
gtkwave obj_dir/waveform.vcd
build:
verilator --cc top.sv --trace --exe tb_top.cpp -I../../.. -CFLAGS "${SDL_CFLAGS}" -LDFLAGS "${SDL_LDFLAGS}"
make -C obj_dir -f Vtop.mk Vtop
clean:
rm -rf ./obj_dir
.PHONY: run wave build clean

View File

@ -0,0 +1,11 @@
module multiplier
(
input wire clk,
input wire signed [15:0] a,
input wire signed [15:0] b,
output wire signed [31:0] product
);
assign product = a * b;
endmodule

View File

@ -0,0 +1,99 @@
module renderer
#(
parameter ITERATIONS = 220,
parameter OUTPUT_WIDTH = 8,
localparam ITERATION_WIDTH = $clog2(ITERATIONS + 1),
localparam SHIFT_AMOUNT = ITERATION_WIDTH - OUTPUT_WIDTH,
localparam FRACTION_BITS = 13
)(
input wire clk,
input wire rst,
input wire start,
input wire [7:0] x,
input wire [7:0] y,
input wire signed [14:0] cx,
input wire signed [14:0] cy,
input wire [2:0] zoom,
output reg done,
output reg [OUTPUT_WIDTH-1:0] iters
);
reg signed [15:0] x_reg;
reg signed [15:0] y_reg;
reg signed [15:0] z_real;
reg signed [15:0] z_imag;
reg [ITERATION_WIDTH-1:0] current_iteration;
wire signed [31:0] a_squared_p;
wire signed [31:0] b_squared_p;
wire signed [31:0] ab_p;
wire signed [31:0] apb_squared;
wire signed [31:0] asb_squared;
wire signed [31:0] ab;
always_ff @(posedge clk) begin
done <= 1'b0;
if (current_iteration == ITERATIONS) begin
x_reg <= '0;
y_reg <= '0;
z_real <= '0;
z_imag <= '0;
current_iteration <= '0;
iters <= '0;
done <= 1'b1;
end else if (apb_squared >= 32'h4 << (2 * FRACTION_BITS)) begin
x_reg <= '0;
y_reg <= '0;
z_real <= '0;
z_imag <= '0;
current_iteration <= '0;
iters <= OUTPUT_WIDTH'(current_iteration >> SHIFT_AMOUNT);
done <= 1'b1;
end else if (current_iteration == 0) begin
// store c for later
x_reg <= cx + (16'(x) << zoom) + 16'hC000;
y_reg <= cy + (16'(y) << zoom) + 16'hC000;
// add c for first iteration.
// no need to include z as it is initially (0, 0)
z_real <= cx + (16'(x) << zoom) + 16'hC000;
z_imag <= cy + (16'(y) << zoom) + 16'hC000;
if (!start) begin
current_iteration <= '0;
end else begin
current_iteration <= current_iteration + 1'b1;
end
end else begin
z_real <= asb_squared[15+FRACTION_BITS:FRACTION_BITS] + x_reg;
z_imag <= ab[15+FRACTION_BITS:FRACTION_BITS] + y_reg;
current_iteration <= current_iteration + 1'b1;
end
if (rst) begin
x_reg <= '0;
y_reg <= '0;
z_real <= '0;
z_imag <= '0;
current_iteration <= '0;
end
end
multiplier m1(.clk(clk), .a(z_real), .b(z_real), .product(a_squared_p));
multiplier m2(.clk(clk), .a(z_imag), .b(z_imag), .product(b_squared_p));
multiplier m3(.clk(clk), .a(z_real), .b(z_imag), .product(ab_p));
assign apb_squared = a_squared_p + b_squared_p;
assign asb_squared = a_squared_p - b_squared_p;
assign ab = ab_p << 1'b1;
endmodule

View File

@ -0,0 +1,172 @@
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <SDL.h>
#include <verilated.h>
#include <verilated_vcd_c.h>
#include "Vtop.h"
constexpr int H_RES = 256;
constexpr int V_RES = 256;
constexpr int S_SCALE = 3;
int main(int argc, char** argv, char** env)
{
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
std::cout << "SDL init failed." << std::endl;
return 1;
}
uint8_t framebuffer[H_RES * V_RES * 2];
unsigned int current = 0;
SDL_Window* sdl_window = nullptr;
SDL_Renderer* sdl_renderer = nullptr;
SDL_Texture* sdl_texture = nullptr;
sdl_window = SDL_CreateWindow("mandelbrot", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
H_RES * S_SCALE, V_RES * S_SCALE, SDL_WINDOW_SHOWN);
if (!sdl_window)
{
std::cout << "Window creation failed: " << SDL_GetError() << std::endl;
return 1;
}
sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if (!sdl_renderer)
{
std::cout << "Renderer creation failed: " << SDL_GetError() << std::endl;
return 1;
}
SDL_RenderSetLogicalSize(sdl_renderer, V_RES, H_RES);
sdl_texture = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_YUY2, SDL_TEXTUREACCESS_TARGET, H_RES, V_RES);
if (!sdl_texture)
{
std::cout << "Texture creation failed: " << SDL_GetError() << std::endl;
return 1;
}
const Uint8* keyb_state = SDL_GetKeyboardState(nullptr);
Vtop* dut = new Vtop;
bool done = false;
vluint64_t sim_time = 0;
Verilated::traceEverOn(true);
VerilatedVcdC* trace = new VerilatedVcdC;
dut->trace(trace, 5);
trace->open("waveform.vcd");
dut->dir = 1;
dut->clk = 1;
dut->eval();
trace->dump(sim_time++);
dut->clk = 0;
dut->eval();
trace->dump(sim_time++);
for (int i = 0; i < 5; i++)
{
dut->clk = 1;
dut->eval();
trace->dump(sim_time++);
dut->clk = 0;
dut->eval();
trace->dump(sim_time++);
}
dut->clk = 1;
dut->eval();
trace->dump(sim_time++);
dut->dir = 0;
dut->clk = 0;
dut->eval();
trace->dump(sim_time++);
bool swapped = false;
bool last = false;
while (true)
{
SDL_Event e;
if (SDL_PollEvent(&e)) { if (e.type == SDL_QUIT) { break; } }
if (keyb_state[SDL_SCANCODE_Q]) { break; }
if (!done || !dut->fin)
{
dut->clk = 1;
dut->eval();
trace->dump(sim_time++);
dut->clk = 0;
dut->eval();
trace->dump(sim_time++);
if (!dut->req || done) { continue; }
framebuffer[current++] = dut->data;
if (current == H_RES * V_RES * 2)
{
current = 0;
SDL_UpdateTexture(sdl_texture, nullptr, framebuffer, H_RES * 2);
SDL_RenderClear(sdl_renderer);
SDL_RenderCopy(sdl_renderer, sdl_texture, nullptr, nullptr);
SDL_RenderPresent(sdl_renderer);
done = true;
}
}
else if (keyb_state[SDL_SCANCODE_N] && !last)
{
if (swapped)
{
SDL_UpdateTexture(sdl_texture, nullptr, framebuffer, H_RES * 2);
SDL_RenderClear(sdl_renderer);
SDL_RenderCopy(sdl_renderer, sdl_texture, nullptr, nullptr);
SDL_RenderPresent(sdl_renderer);
swapped = false;
}
else
{
uint8_t fb2[V_RES * H_RES * 2];
for (int i = 0; i < V_RES * H_RES * 2; i += 2)
{
float zr = 0, zi = 0;
const float cr = (i % (H_RES * 2)) / 192.0f - 2.1f;
const float ci = (i / (H_RES * 2)) / 96.0f - 1.5f;
fb2[i] = 62;
fb2[i + 1] = 128;
for (int iter = 0; iter < 64; iter++)
{
if (zr * zr + zi * zi >= 4)
{
fb2[i] = 16.0f * sqrt(iter) + 62;
break;
}
float tzr = zr * zr - zi * zi + cr;
zi = 2 * zr * zi + ci;
zr = tzr;
}
}
SDL_UpdateTexture(sdl_texture, nullptr, fb2, H_RES * 2);
SDL_RenderClear(sdl_renderer);
SDL_RenderCopy(sdl_renderer, sdl_texture, nullptr, nullptr);
SDL_RenderPresent(sdl_renderer);
swapped = true;
}
}
last = keyb_state[SDL_SCANCODE_N];
}
trace->close();
delete trace;
delete dut;
return 0;
}

View File

@ -0,0 +1,131 @@
module top
(
input wire clk,
input wire dir,
inout wire req,
output wire fin,
inout wire [7:0] data
);
localparam RENDER_COUNT = 4;
reg req_last;
reg [7:0] waddr;
reg [7:0] raddr;
wire [7:0] command;
ram command_buffer(.wclk(clk), .rclk(clk), .waddr(waddr), .raddr(raddr), .data_in(data), .write_en(dir && req), .data_out(command));
wire [7:0] iters[RENDER_COUNT];
wire [7:0] x[RENDER_COUNT];
wire [7:0] y[RENDER_COUNT];
wire [RENDER_COUNT-1:0] renderer_done;
reg [RENDER_COUNT-1:0] renderer_done_r;
wire coords_fin;
reg coords_inc;
reg coords_inc_last;
reg [5:0] coords_fin_last;
genvar ri;
generate
for (ri = 0; ri < RENDER_COUNT; ri = ri + 1) begin
renderer r(.clk(clk), .rst(dir), .start(!dir && !coords_fin && !renderer_done[ri] && !renderer_done_r[ri]), .x(x[ri]), .y(y[ri]), .cx(15'h1000), .cy(15'h2000), .zoom(3'd6), .done(renderer_done[ri]), .iters(iters[ri]));
end
endgenerate
coords #(.POS_COUNT(RENDER_COUNT)) coords_inst(.clk(clk), .rst(dir), .inc(coords_inc), .x(x), .y(y), .finished(coords_fin));
wire fb_clk;
reg [16:0] fb_addr;
wire fb_we;
wire [15:0] fb_data_out;
reg [15:0] fb_data_out_last;
reg fb_half_out;
spram_big fb
(
.clk(fb_clk),
.we
({
{ fb_we, fb_we, fb_we, fb_we },
{ fb_we, fb_we, fb_we, fb_we },
{ fb_we, fb_we, fb_we, fb_we },
{ fb_we, fb_we, fb_we, fb_we }
}),
.addr(fb_addr[15:0]),
.data_in
({
{ 8'd128, iters[0] + 8'd16 },
{ 8'd128, iters[1] + 8'd16 },
{ 8'd128, iters[2] + 8'd16 },
{ 8'd128, iters[3] + 8'd16 }
}),
.data_out(fb_data_out)
);
always_ff @(posedge clk) begin
req_last <= req;
coords_fin_last[5:1] <= coords_fin_last[4:0];
coords_fin_last[0] <= coords_fin && !dir;
coords_inc_last <= coords_inc && !dir;
if (dir) begin
renderer_done_r <= '0;
end else begin
integer i;
for (i = 0; i < RENDER_COUNT; i = i + 1) begin
if (renderer_done[i]) begin
renderer_done_r[i] <= 1;
end
end
if (renderer_done_r == '1) begin
renderer_done_r <= '0;
coords_inc <= 1;
end else begin
coords_inc <= 0;
end
end
if (dir) begin
raddr <= 0;
fb_addr <= 0;
fb_half_out <= 0;
if (req && req_last) begin
waddr <= waddr + 1;
end else begin
waddr <= 0;
end
end else if (coords_fin) begin
if (!coords_fin_last[0] || !coords_fin_last[1]) begin
fb_addr <= 0;
fb_half_out <= 0;
end else begin
fb_half_out <= !fb_half_out;
if (fb_half_out) begin
fb_data_out_last <= fb_data_out;
fb_addr <= fb_addr + 1;
end
end
end else if (coords_inc_last) begin
fb_addr <= fb_addr + RENDER_COUNT;
end
end
assign fb_clk = clk;
assign fb_we = coords_inc && !coords_fin;
assign fin = !dir && coords_fin_last[5] && fb_addr >= 65536;
assign req = dir ? 'Z : coords_fin_last[5];
assign data = dir ? 'Z : (fb_half_out ? fb_data_out_last[15:8] : fb_data_out_last[7:0]);
endmodule

31
ice/ram.sv Normal file
View File

@ -0,0 +1,31 @@
module ram
#(
parameter ADDR_WIDTH = 8,
parameter DATA_WIDTH = 8
)(
input wire wclk,
input wire rclk,
input wire [ADDR_WIDTH-1:0] waddr,
input wire [ADDR_WIDTH-1:0] raddr,
input wire [DATA_WIDTH-1:0] data_in,
input wire write_en,
output wire [DATA_WIDTH-1:0] data_out
);
reg [DATA_WIDTH-1:0] data_out_r;
reg [DATA_WIDTH-1:0] mem[(1<<ADDR_WIDTH)-1:0];
always @(posedge wclk) begin
if (write_en) begin
mem[waddr] <= data_in;
end
end
always @(posedge rclk) begin
data_out_r <= mem[raddr];
end
assign data_out = data_out_r;
endmodule

31
ice/spram.sv Normal file
View File

@ -0,0 +1,31 @@
module spram
(
input wire clk,
input wire [3:0] we,
input wire [13:0] addr,
input wire [15:0] data_in,
output wire [15:0] data_out
);
`ifdef VERILATOR
reg [15:0] mem[16384];
reg [15:0] data_out_r;
always_ff @(posedge clk) begin
integer i;
for (i = 0; i < 4; i = i + 1) begin
if (we[i]) begin
mem[addr][(3+4*i)+:4] <= data_in[(3+4*i)+:4];
end
end
data_out_r <= mem[addr];
end
assign data_out = data_out_r;
`else
SP256K bb_spram_inst(.AD(addr), .DI(data_in), .MASKWE(we), .WE(|we), .CS('1), .CK(clk), .STDBY('0), .SLEEP('0), .PWROFF_N('1), .DO(data_out));
`endif
endmodule

21
ice/spram_big.sv Normal file
View File

@ -0,0 +1,21 @@
module spram_big
(
input wire clk,
input wire [3:0] we[4],
input wire [15:0] addr,
input wire [15:0] data_in[4],
output wire [15:0] data_out
);
wire [15:0] datas_out[4];
genvar i;
generate
for (i = 0; i < 4; i = i + 1) begin
spram spram_inst(.clk(clk), .we(we[i]), .addr(addr[15:2]), .data_in(data_in[i]), .data_out(datas_out[i]));
end
endgenerate
assign data_out = datas_out[addr[1:0]];
endmodule

129
main.cpp
View File

@ -1,30 +1,48 @@
#include <ice_fpga.h> #include <ice_fpga.h>
#include <ice_led.h> #include <ice_led.h>
#include <ice_usb.h> #include <ice_usb.h>
#include <ice_spi.h>
#include <tusb.h> #include <tusb.h>
#include <boards/pico_ice.h>
#include <bsp/board_api.h> #include <bsp/board_api.h>
#include <hardware/clocks.h>
#include <pico/stdio.h>
#include <hardware/gpio.h>
#include <hardware/uart.h> #include <hardware/uart.h>
#include <pico/stdio.h>
#include "fpga.pio.h"
static const PIO pio = pio0;
static uint sm;
static uint8_t frame_buffer[FRAME_WIDTH * FRAME_HEIGHT * 2] = { };
static uint8_t command_buffer[256] = { };
static void video_task(); static void video_task();
static void start_next_frame();
static bool finished = false;
int main() int main()
{ {
tusb_init();
stdio_init_all(); stdio_init_all();
uart_init(uart0, 115200);
gpio_set_function(0, GPIO_FUNC_UART);
gpio_set_function(1, GPIO_FUNC_UART);
ice_led_init(); ice_led_init();
ice_usb_init(); ice_usb_init();
ice_fpga_init(12); ice_fpga_init(4);
ice_fpga_start(); ice_fpga_start();
gpio_pull_up(DIR_PIN);
gpio_pull_up(REQ_PIN);
gpio_init(FIN_PIN);
gpio_pull_up(FIN_PIN);
const uint offset = pio_add_program(pio, &fpga_program);
sm = pio_claim_unused_sm(pio, true);
fpga_program_init(pio, sm, offset, 0, DIR_PIN, FIN_PIN);
pio_sm_set_enabled(pio, sm, true);
tud_init(0); tud_init(0);
if (board_init_after_tusb) if (board_init_after_tusb)
@ -34,6 +52,17 @@ int main()
while (true) while (true)
{ {
uint8_t val = 0;
for (int i = 0; i < 8; i++)
{
val |= gpio_get(i) << i;
}
printf("%d %d %d | %3d |", gpio_get(DIR_PIN), gpio_get(REQ_PIN), gpio_get(FIN_PIN), val);
for (int i = 0; i < 12; i++)
{
printf(" %3d", frame_buffer[i]);
}
printf("\n");
tud_task(); tud_task();
video_task(); video_task();
} }
@ -41,60 +70,19 @@ int main()
} }
static unsigned int interval_ms = 1000 / FRAME_RATE; static unsigned int interval_ms = 1000 / FRAME_RATE;
static unsigned int frame_num = 0;
static bool tx_busy = false; static bool tx_busy = false;
static bool rendering = false;
static uint8_t frame_buffer[FRAME_WIDTH * FRAME_HEIGHT * 16 / 8] = { }; static bool is_rendering() { return rendering || !pio_interrupt_get(pio, 0); }
static void fill_color_bar(uint8_t* buffer, const unsigned int start_position)
{
static constexpr uint8_t bar_color[8][4] =
{
/* Y, U, Y, V */
{ 235, 128, 235, 128 }, /* 100% White */
{ 219, 16, 219, 138 }, /* Yellow */
{ 188, 154, 188, 16 }, /* Cyan */
{ 173, 42, 173, 26 }, /* Green */
{ 78, 214, 78, 230 }, /* Magenta */
{ 63, 102, 63, 240 }, /* Red */
{ 32, 240, 32, 118 }, /* Blue */
{ 16, 128, 16, 128 }, /* Black */
};
uint8_t* p;
const uint8_t* end = &buffer[FRAME_WIDTH * 2];
const unsigned int index = (FRAME_WIDTH / 2 - 1) - (start_position % (FRAME_WIDTH / 2));
p = &buffer[index * 4];
for (unsigned int i = 0; i < 8; i++)
{
for (int j = 0; j < FRAME_WIDTH / (2 * 8); j++)
{
memcpy(p, &bar_color[i], 4);
p += 4;
if (p >= end) { p = buffer; }
}
}
p = &buffer[FRAME_WIDTH * 2];
for (unsigned int i = 1; i < FRAME_HEIGHT; i++)
{
memcpy(p, buffer, FRAME_WIDTH * 2);
p += FRAME_WIDTH * 2;
}
}
void video_task() void video_task()
{ {
static bool already_sent = false; static bool already_sent = false;
static unsigned int start_ms = 0; static unsigned int start_ms = 0;
// don't send data if not streaming
if (!tud_video_n_streaming(0, 0)) if (!tud_video_n_streaming(0, 0))
{ {
already_sent = false; already_sent = false;
frame_num = 0;
return; return;
} }
@ -104,26 +92,51 @@ void video_task()
tx_busy = true; tx_busy = true;
start_ms = board_millis(); start_ms = board_millis();
fill_color_bar(frame_buffer, frame_num); tud_video_n_frame_xfer(0, 0, frame_buffer, FRAME_WIDTH * FRAME_HEIGHT * 2);
tud_video_n_frame_xfer(0, 0, frame_buffer, FRAME_WIDTH * FRAME_HEIGHT * 16 / 8); return;
} }
const unsigned int cur = board_millis(); const unsigned int cur = board_millis();
if (cur - start_ms < interval_ms) { return; } if (cur - start_ms < interval_ms) { return; }
if (tx_busy) { return; } if (tx_busy) { return; }
if (is_rendering()) { return; }
start_ms += interval_ms; start_ms += interval_ms;
tx_busy = true; tx_busy = true;
fill_color_bar(frame_buffer, frame_num); tud_video_n_frame_xfer(0, 0, frame_buffer, FRAME_WIDTH * FRAME_HEIGHT * 2);
tud_video_n_frame_xfer(0, 0, frame_buffer, FRAME_WIDTH * FRAME_HEIGHT * 16 / 8); }
void start_next_frame()
{
if (is_rendering()) { return; }
rendering = true;
command_buffer[0] = (command_buffer[0] + 4) % 256;
if (command_buffer[0] == 0)
{
command_buffer[1] = (command_buffer[1] + 16) % 256;
}
dma_channel_set_trans_count(frame_dma_channel, FRAME_WIDTH * FRAME_HEIGHT * 2, false);
dma_channel_set_write_addr(frame_dma_channel, frame_buffer, false);
dma_channel_set_trans_count(command_dma_channel, 2, false);
dma_channel_set_read_addr(command_dma_channel, command_buffer, true);
// clear irq to indicate ready
while (pio_interrupt_get(pio, 0))
{
pio_interrupt_clear(pio, 0);
}
rendering = false;
} }
void tud_video_frame_xfer_complete_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx) void tud_video_frame_xfer_complete_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx)
{ {
tx_busy = false; tx_busy = false;
start_next_frame();
frame_num++;
} }
int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, const video_probe_and_commit_control_t* parameters) int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, const video_probe_and_commit_control_t* parameters)

View File

@ -69,11 +69,11 @@
// Must be a multiple of flash page size // Must be a multiple of flash page size
#define CFG_TUD_DFU_XFER_BUFSIZE 256 #define CFG_TUD_DFU_XFER_BUFSIZE 256
#define CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE 256 #define CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE 1023
#define CFG_TUD_VIDEO_STREAMING_BULK 0 #define CFG_TUD_VIDEO_STREAMING_BULK 0
#define FRAME_WIDTH 32 #define FRAME_WIDTH 256
#define FRAME_HEIGHT 18 #define FRAME_HEIGHT 256
#define FRAME_RATE 60 #define FRAME_RATE 60
// Temporarily here until ice_usb.h has necessary info // Temporarily here until ice_usb.h has necessary info