From 19523688caa5c70643c16fc0d47d30019a60dd84 Mon Sep 17 00:00:00 2001 From: Sylvain Lefebvre Date: Wed, 6 Dec 2023 13:36:56 +0100 Subject: [PATCH 1/2] wip on hrdw display buffer --- learn-silice/classroom/soc_wave_player/firmware/config.c | 1 + learn-silice/classroom/soc_wave_player/firmware/config.h | 1 + learn-silice/classroom/soc_wave_player/firmware/display.c | 7 +++++-- learn-silice/classroom/soc_wave_player/firmware/display.h | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/learn-silice/classroom/soc_wave_player/firmware/config.c b/learn-silice/classroom/soc_wave_player/firmware/config.c index 72596073..de5b8ac6 100644 --- a/learn-silice/classroom/soc_wave_player/firmware/config.c +++ b/learn-silice/classroom/soc_wave_player/firmware/config.c @@ -8,4 +8,5 @@ volatile int* const OLED_RST = (int*)0x10010; // 10000000000010000 volatile int* const UART = (int*)0x10020; // 10000000000100000 volatile int* const SDCARD = (int*)0x10080; // 10000000010000000 volatile int* const BUTTONS = (int*)0x10100; // 10000000100000000 +volatile int* const DISPLAY = (int*)0x14000; // 10100000000000000 volatile int* const AUDIO = (int*)0x18000; // 11000000000000000 diff --git a/learn-silice/classroom/soc_wave_player/firmware/config.h b/learn-silice/classroom/soc_wave_player/firmware/config.h index f552fa61..69ac3a31 100644 --- a/learn-silice/classroom/soc_wave_player/firmware/config.h +++ b/learn-silice/classroom/soc_wave_player/firmware/config.h @@ -11,3 +11,4 @@ extern volatile int* const UART; extern volatile int* const SDCARD; extern volatile int* const AUDIO; extern volatile int* const BUTTONS; +extern volatile int* const DISPLAY; diff --git a/learn-silice/classroom/soc_wave_player/firmware/display.c b/learn-silice/classroom/soc_wave_player/firmware/display.c index 15bf8c6b..6c5152f4 100644 --- a/learn-silice/classroom/soc_wave_player/firmware/display.c +++ b/learn-silice/classroom/soc_wave_player/firmware/display.c @@ -11,9 +11,10 @@ int cursor_y; unsigned char front_color; unsigned char back_color; -unsigned char framebuffer[128*128]; +// unsigned char framebuffer[128*128]; +#define framebuffer ((volatile unsigned char *)DISPLAY) -unsigned char *display_framebuffer() +volatile unsigned char *display_framebuffer() { return framebuffer; } @@ -61,6 +62,7 @@ void display_putchar(int c) void display_refresh() { +#if 0 unsigned char *ptr = framebuffer; for (int i=0;i<128*128;i++) { unsigned char c = (*ptr)>>2; @@ -68,6 +70,7 @@ void display_refresh() oled_pix(c,c,c); oled_wait(); } +#endif } void dual_putchar(int c) diff --git a/learn-silice/classroom/soc_wave_player/firmware/display.h b/learn-silice/classroom/soc_wave_player/firmware/display.h index ea802d17..34ce4857 100644 --- a/learn-silice/classroom/soc_wave_player/firmware/display.h +++ b/learn-silice/classroom/soc_wave_player/firmware/display.h @@ -9,4 +9,4 @@ void display_set_front_back_color(unsigned char f,unsigned char b); void display_putchar(int c); void display_refresh(); void dual_putchar(int c); -unsigned char *display_framebuffer(); +volatile unsigned char *display_framebuffer(); From 2a93fce73f8227dd3740a250985b5b5e62536588 Mon Sep 17 00:00:00 2001 From: Sylvain Lefebvre Date: Thu, 7 Dec 2023 20:02:32 +0100 Subject: [PATCH 2/2] classroom, hardware frame buffer as step7 --- .../classroom/soc_wave_player/Makefile | 13 +++- .../soc_wave_player/firmware/Makefile | 2 +- .../soc_wave_player/firmware/display.c | 7 +- .../firmware/step7_hrdw_screen.c | 60 +++++++++++++++++ .../soc_wave_player/hardware/main.si | 64 ++++++++++++++++--- 5 files changed, 132 insertions(+), 14 deletions(-) create mode 100644 learn-silice/classroom/soc_wave_player/firmware/step7_hrdw_screen.c diff --git a/learn-silice/classroom/soc_wave_player/Makefile b/learn-silice/classroom/soc_wave_player/Makefile index adf561ad..a638be17 100644 --- a/learn-silice/classroom/soc_wave_player/Makefile +++ b/learn-silice/classroom/soc_wave_player/Makefile @@ -78,6 +78,17 @@ endif step6.si : hardware/main.si python ../tools/solutions.py -i hardware/main.si -s LED,AUDIO,SCREEN,BTN,SD,STREAM > $@ +step7: step7.si + make -C firmware $(FIRMWARE) DEFINES="-DHWFBUFFER" +ifeq ($(BOARD),verilator) + silice-make.py -s $@.si -b $(BOARD) -p basic,oled -o BUILD_$(subst :,_,$@) $(ARGS) +else + silice-make.py -s $@.si -b $(BOARD) -p basic,audio,oled,buttons,sdcard -o BUILD_$(subst :,_,$@) $(ARGS) +endif + +step7.si : hardware/main.si + python ../tools/solutions.py -i hardware/main.si -s LED,AUDIO,SCREEN,BTN,SD,STREAM,HWFBUFFER > $@ + final: final.si make -C firmware $(FIRMWARE) ifeq ($(BOARD),verilator) @@ -87,7 +98,7 @@ else endif final.si : hardware/main.si - python ../tools/solutions.py -i hardware/main.si -s LED,AUDIO,SCREEN,BTN,SD,STREAM,PWM > $@ + python ../tools/solutions.py -i hardware/main.si -s LED,AUDIO,SCREEN,BTN,SD,STREAM,HWFBUFFER,PWM > $@ clean: make -C firmware clean diff --git a/learn-silice/classroom/soc_wave_player/firmware/Makefile b/learn-silice/classroom/soc_wave_player/firmware/Makefile index 5328e849..19c26a93 100644 --- a/learn-silice/classroom/soc_wave_player/firmware/Makefile +++ b/learn-silice/classroom/soc_wave_player/firmware/Makefile @@ -12,7 +12,7 @@ $(PRGS): %: %.o $(OBJS) $(ARCH)-objdump --disassemble code.elf > code.s %.o : %.c - $(CC) -fno-builtin -fno-unroll-loops -Os -fno-stack-protector -fno-pic -march=rv32i -mabi=ilp32 -c $< -o $@ + $(CC) -fno-builtin -fno-unroll-loops $(DEFINES) -Os -fno-stack-protector -fno-pic -march=rv32i -mabi=ilp32 -c $< -o $@ %.o : %.s $(AS) -march=rv32i -mabi=ilp32 $< -o $@ diff --git a/learn-silice/classroom/soc_wave_player/firmware/display.c b/learn-silice/classroom/soc_wave_player/firmware/display.c index 6c5152f4..f5478628 100644 --- a/learn-silice/classroom/soc_wave_player/firmware/display.c +++ b/learn-silice/classroom/soc_wave_player/firmware/display.c @@ -11,8 +11,11 @@ int cursor_y; unsigned char front_color; unsigned char back_color; -// unsigned char framebuffer[128*128]; +#ifdef HWFBUFFER #define framebuffer ((volatile unsigned char *)DISPLAY) +#else +unsigned char framebuffer[128*128]; +#endif volatile unsigned char *display_framebuffer() { @@ -62,7 +65,7 @@ void display_putchar(int c) void display_refresh() { -#if 0 +#ifndef HWFBUFFER unsigned char *ptr = framebuffer; for (int i=0;i<128*128;i++) { unsigned char c = (*ptr)>>2; diff --git a/learn-silice/classroom/soc_wave_player/firmware/step7_hrdw_screen.c b/learn-silice/classroom/soc_wave_player/firmware/step7_hrdw_screen.c new file mode 100644 index 00000000..64469a46 --- /dev/null +++ b/learn-silice/classroom/soc_wave_player/firmware/step7_hrdw_screen.c @@ -0,0 +1,60 @@ +// @sylefeb 2022-01-10 +// MIT license, see LICENSE_MIT in Silice repo root +// https://github.com/sylefeb/Silice/ + +#include "config.h" +#include "std.h" +#include "oled.h" +#include "display.h" +#include "printf.h" + +#ifndef HWFBUFFER +#error This firmware needs HWFBUFFER defined +#endif + +void main() +{ + // install putchar handler for printf + f_putchar = display_putchar; + // init display + oled_init(); + oled_fullscreen(); + oled_clear(0); + // print message + display_set_cursor(0,0); + display_set_front_back_color(255,0); + + // gradient background + for (int i = 0 ; i < 128; ++i) { + for (int j = 0 ; j < 128; ++j) { + display_framebuffer()[i + (j << 7)] = i; + } + } + + // bouncing text + int dx = 3; + int dy = 1; + int x = 0; + int y = 0; + while (1) { + display_set_cursor(x,y); + printf("Hello world!"); + x += dx; + if (x > 64) { + x = 64; + dx = -dx; + } else if (x < 0) { + x = 0; + dx = -dx; + } + y += dy; + if (y > 108) { + y = 108; + y = -dy; + } else if (y < 0) { + y = 0; + dy = -dy; + } + } + +} diff --git a/learn-silice/classroom/soc_wave_player/hardware/main.si b/learn-silice/classroom/soc_wave_player/hardware/main.si index 53ce2939..b24a0d83 100644 --- a/learn-silice/classroom/soc_wave_player/hardware/main.si +++ b/learn-silice/classroom/soc_wave_player/hardware/main.si @@ -60,8 +60,8 @@ $$if not Solution_PWM then } $$else uint8 counter = 0; - uint4 low = 4b0; - uint4 high = 4b1; + uint4 low = 0; + uint4 high = 15; always { uint8 frac = audio_in; audio_out = counter < frac ? high : low; @@ -129,16 +129,20 @@ $$end $$if Solution_SCREEN then // SPIscreen (OLED) controller chip - uint1 displ_dta_or_cmd <: prev_wdata[10,1]; - uint8 displ_byte <: prev_wdata[0,8]; oled display( - data_or_command <: displ_dta_or_cmd, - byte <: displ_byte, oled_din :> oled_mosi, oled_clk :> oled_clk, oled_dc :> oled_dc, ); $$end +$$if Solution_HWFBUFFER then + // allocate a BRAM for the display pixels + simple_dualport_bram uint8 frame_buffer[$128*128$] = uninitialized; + uint1 fb_enabled = 0; + uint14 fb_pixcount = 0; + uint3 fb_channel = 3b010; + uint17 fb_wait = 1; +$$end $$if Solution_SPIflash then $$if not SPIFLASH then @@ -243,6 +247,22 @@ $$if Solution_STREAM then : (audio_buffer_sample+1) // go to next sample ); audio_counter = (audio_counter == $PERIOD$) ? 0 : (audio_counter+1); +$$end +$$if Solution_HWFBUFFER then + // ---- hardware display buffer + frame_buffer.wenable1 = 0; + display.enable = fb_enabled & fb_wait[0,1]; + display.data_or_command = 1; + display.byte = frame_buffer.rdata0; + frame_buffer.addr0 = fb_pixcount; + fb_channel = (fb_enabled & fb_wait[0,1]) + ? {fb_channel[0,2],fb_channel[2,1]} + : fb_channel; + fb_wait = (fb_enabled) ? {fb_wait[0,16],fb_wait[16,1]} + : fb_wait; + fb_pixcount = (fb_enabled & fb_wait[0,1] & fb_channel[0,1]) + ? fb_pixcount + 1 + : fb_pixcount; $$end // ---- check whether the CPU read from or wrote to a peripheral address uint1 peripheral = prev_mem_addr[$periph_bit$,1]; @@ -255,7 +275,7 @@ $$if Solution_LED then uint1 leds_access = prev_mem_addr[ 0,1]; $$end $$if Solution_SCREEN then - uint1 display_en_access = prev_mem_addr[ 1,1]; + uint1 display_direct_access = prev_mem_addr[ 1,1]; uint1 display_reset_access = prev_mem_addr[ 2,1]; $$end $$if Solution_UART then @@ -269,6 +289,9 @@ $$if Solution_SD then $$end $$if Solution_BTN then uint1 button_access = prev_mem_addr[ 6,1]; +$$end +$$if Solution_HWFBUFFER then + uint1 framebuffer_access = prev_mem_addr[$periph_bit-2$,1]; $$end // ---- memory access CPU <-> BRAM (reads and writes) // reads RAM, peripherals => CPU @@ -295,19 +318,29 @@ $$end ram.wdata = memio.wdata; ram.addr = memio.addr; // writes CPU => peripherals +$$if Solution_HWFBUFFER and Solution_STREAM then + if (peripheral_w & ~audio_access & ~framebuffer_access) { +$$else $$if Solution_STREAM then if (peripheral_w & ~audio_access) { $$else if (peripheral_w) { $$end +$$end $$if Solution_LED then /// LEDs leds = leds_access ? prev_wdata[0,8] : leds; $$end $$if Solution_SCREEN then /// display - // -> whether to send command or data - display.enable = display_en_access & (prev_wdata[9,1] | prev_wdata[10,1]); + if (display_direct_access) { + // -> whether to send command or data + display.enable = (prev_wdata[9,1] | prev_wdata[10,1]); + // -> byte to send + display.byte = prev_wdata[0,8]; + // -> data or command + display.data_or_command = prev_wdata[10,1]; + } // -> SPIscreen reset oled_resn = ~ (display_reset_access & prev_wdata[0,1]); $$end @@ -366,16 +399,27 @@ $$if SIMULATION then $$end } -$$if Solution_STREAM then +$$if Solution_STREAM or Solution_HWFBUFFER then if (peripheral_w) { uint2 which = prev_mem_rw[1,2] | {2{prev_mem_rw[3,1]}}; // ^^^^^ produces 0,1,2,3 based on write mask +$$if Solution_STREAM then + // ---- audio audio_buffer.wdata1 = prev_wdata >> {which,3b0}; // ^^^ sample to be written ^^ (shift due to 32bits addressing) audio_buffer.addr1 = audio_buffer_start_waddr | {prev_mem_addr[0,7],2b0}//addr from CPU (32bits) | which; // sample address audio_buffer.wenable1 = audio_access; // write sample +$$end +$$if Solution_HWFBUFFER then + // ---- display + frame_buffer.wenable1 = framebuffer_access; + fb_enabled = fb_enabled | framebuffer_access; + frame_buffer.addr1 = {prev_mem_addr[0,12],which}; //addr from CPU (32bits) + uint8 clr = prev_wdata[{which,3b000},8]; // get 8 bit channel value + frame_buffer.wdata1 = {2b00,clr[2,6]}; // remap to 6 bits per channel +$$end } $$end