Гуглосиликон на халяву!

Печатные платы, программируемая логика, разработка и изготовление аппаратуры

Moderator: Shaos

User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Гуглосиликон на халяву!

Post by Shaos »

Впредь надо будет интерфейс шины Wishbone задействовать - проц Caravel может с пользовательским дизайном через эту шину общаться - можно на разные адреса вешать регистры и вообще память цеплять - вот тут подробности с примером: https://vlsi.jp/Introduction_to_OpenMPW.html
Screenshot from 2023-06-30 22-39-15.png
Пример на верилоге с тремя регистрами, доступными на запись и на чтение:

Code: Select all

module wb_interface #(
    parameter TEST_CSR0 = 32'h3000_0000,
    parameter TEST_CSR1 = 32'h3000_0004,
    parameter TEST_CSR2 = 32'h3000_0008
)(
    // wishbone signals
    input   wire        wb_clk_i,
    input   wire        wb_rst_i,
    input   wire        wbs_stb_i,
    input   wire        wbs_cyc_i,
    input   wire        wbs_we_i,
    input   wire [3:0]  wbs_sel_i,
    input   wire [31:0] wbs_dat_i,
    input   wire [31:0] wbs_adr_i,
    output  reg         wbs_ack_o,
    output  reg  [31:0] wbs_dat_o,
    // CSRs
    output  reg  [31:0] test_csr0,
    output  reg  [31:0] test_csr1,
    output  reg  [31:0] test_csr2
);

    localparam WB_IDLE  = 2'b00;
    localparam WB_READ  = 2'b01;
    localparam WB_WRITE = 2'b10;

    reg [1:0] wb_state;

    always @(posedge wb_clk_i) begin
        if(wb_rst_i) begin
            wb_state    <= WB_IDLE;
            wbs_ack_o   <= 1'b0;
        end else begin
            case(wb_state)
                WB_IDLE : begin
                    wbs_ack_o   <= 1'b0;
                    if(wbs_stb_i && wbs_cyc_i) begin
                        if(wbs_we_i) begin
                            wb_state <= WB_WRITE;
                        end else begin
                            wb_state <= WB_READ;
                        end
                    end
                end
                WB_READ : begin
                    wb_state    <= WB_IDLE;
                    wbs_ack_o   <= 1'b1;
                    case(wbs_adr_i)
                        TEST_CSR0 : begin
                            wbs_dat_o[7:0]   <= wbs_sel_i[0] ? test_csr0[7:0] : 8'h00;
                            wbs_dat_o[15:8]  <= wbs_sel_i[1] ? test_csr0[15:0] : 8'h00;
                            wbs_dat_o[23:16] <= wbs_sel_i[2] ? test_csr0[23:16] : 8'h00;
                            wbs_dat_o[31:24] <= wbs_sel_i[3] ? test_csr0[31:24] : 8'h00;
                        end
                        TEST_CSR1 : begin
                            wbs_dat_o[7:0]   <= wbs_sel_i[0] ? test_csr1[7:0] : 8'h00;
                            wbs_dat_o[15:8]  <= wbs_sel_i[1] ? test_csr1[15:0] : 8'h00;
                            wbs_dat_o[23:16] <= wbs_sel_i[2] ? test_csr1[23:16] : 8'h00;
                            wbs_dat_o[31:24] <= wbs_sel_i[3] ? test_csr1[31:24] : 8'h00;
                        end
                        TEST_CSR2 : begin
                            wbs_dat_o[7:0]   <= wbs_sel_i[0] ? test_csr2[7:0] : 8'h00;
                            wbs_dat_o[15:8]  <= wbs_sel_i[1] ? test_csr2[15:0] : 8'h00;
                            wbs_dat_o[23:16] <= wbs_sel_i[2] ? test_csr2[23:16] : 8'h00;
                            wbs_dat_o[31:24] <= wbs_sel_i[3] ? test_csr2[31:24] : 8'h00;
                        end
                        default   : begin
                            wbs_dat_o <= 32'h0000_0000;
                        end
                    endcase
                end
                WB_WRITE : begin
                    wb_state    <= WB_IDLE;
                    wbs_ack_o   <= 1'b1;
                    case(wbs_adr_i)
                        TEST_CSR0 : begin
                            test_csr0[7:0]   <= wbs_sel_i[0] ? wbs_dat_i[7:0] : 8'h00;
                            test_csr0[15:8]  <= wbs_sel_i[1] ? wbs_dat_i[15:8] : 8'h00;
                            test_csr0[23:16] <= wbs_sel_i[2] ? wbs_dat_i[23:16] : 8'h00;
                            test_csr0[31:24] <= wbs_sel_i[3] ? wbs_dat_i[31:24] : 8'h00;
                        end
                        TEST_CSR1 : begin
                            test_csr1[7:0]   <= wbs_sel_i[0] ? wbs_dat_i[7:0] : 8'h00;
                            test_csr1[15:8]  <= wbs_sel_i[1] ? wbs_dat_i[15:8] : 8'h00;
                            test_csr1[23:16] <= wbs_sel_i[2] ? wbs_dat_i[23:16] : 8'h00;
                            test_csr1[31:24] <= wbs_sel_i[3] ? wbs_dat_i[31:24] : 8'h00;
                        end
                        TEST_CSR2 : begin
                            test_csr2[7:0]   <= wbs_sel_i[0] ? wbs_dat_i[7:0] : 8'h00;
                            test_csr2[15:8]  <= wbs_sel_i[1] ? wbs_dat_i[15:8] : 8'h00;
                            test_csr2[23:16] <= wbs_sel_i[2] ? wbs_dat_i[23:16] : 8'h00;
                            test_csr2[31:24] <= wbs_sel_i[3] ? wbs_dat_i[31:24] : 8'h00;
                        end
                    endcase
                end
            endcase
        end
    end

endmodule
You do not have the required permissions to view the files attached to this post.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Гуглосиликон на халяву!

Post by Shaos »

Научился прошивать тестовую программку в девборду :mrgreen:
https://github.com/efabless/caravel_board/blob/main/gf180/blink/blink.c

Code: Select all

python3.8 ../util/caravel_hkflash.py blink.hex
Success: Found one matching FTDI device at ftdi://ftdi:232h:1:15/1
 
Caravel data:
   mfg        = 0456
   product    = 20
   project ID = 180058d2
 
Resetting Flash...
status = 0x00
 
JEDEC = b'ef4016'
Erasing chip...
done
status = 0x0
setting address to 0x0
addr 0x0: flash page write successful
addr 0x100: flash page write successful
addr 0x200: flash page write successful
addr 0x300: flash page write successful
addr 0x400: flash page write successful
addr 0x500: flash page write successful
addr 0x600: flash page write successful

total_bytes = 1652
status reg_1 = 0x0
status reg_2 = 0x2
************************************
verifying...
************************************
status reg_1 = 0x0
status reg_2 = 0x2
setting address to 0x0
addr 0x0: read compare successful
addr 0x100: read compare successful
addr 0x200: read compare successful
addr 0x300: read compare successful
addr 0x400: read compare successful
addr 0x500: read compare successful
addr 0x600: read compare successful

total_bytes = 1652
pll_trim = b'4b'

python3.8 ../util/caravel_hkstop.py
Success: Found one matching FTDI device at ftdi://ftdi:232h:1:15/1
Теперь можно начинать писать свою программку для тестирования пользовательских внутренностей...
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Гуглосиликон на халяву!

Post by Shaos »

На борту девборды установлен генератор 10 МГц - и похоже чип на такой частоте и работает т.к. вот такая функция:

Code: Select all

void delay(const int d)
{

    /* Configure timer for a single-shot countdown */
	reg_timer0_config = 0;
	reg_timer0_data = d;
    reg_timer0_config = 1;

    // Loop, waiting for value to reach zero
   reg_timer0_update = 1;  // latch current value
   while (reg_timer0_value > 0) {
           reg_timer0_update = 1;
   }

}
будучи вызвана с аргументом 5000000 выполняется ровно полсекунды
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Гуглосиликон на халяву!

Post by Shaos »

Чтобы USB-шнурок мог использоваться не только для прошивки, но и для последовательного взаимодействия нужно поставить вот этот джампер:
GF180-E5-serial.jpg
После этого заработало

Code: Select all

 print("Hello World !!");
на скорости 9600 :dj:
You do not have the required permissions to view the files attached to this post.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Гуглосиликон на халяву!

Post by Shaos »

Люди нашли способ настраивать входы-выходы так, чтобы можно было из проца подавать уровни на входы пользовательского модуля и читать выходы - теперь можно полноценно тестироваться :)
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Гуглосиликон на халяву!

Post by Shaos »

Shaos wrote:Всё работает, кроме C-гейта что внизу схемы :(

Написал программку для встроенного проца - всё работает как надо, включая C-гейт :mrgreen:
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Гуглосиликон на халяву!

Post by Shaos »

Прошивальная питоновская утилитка у них периодически сбоила, поэтому я её им пофиксил и заслал пул-реквест :roll:

https://github.com/efabless/caravel_board/pull/85

P.S. Иногда оно всё же перехлёстывается - надо переписывать...
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Гуглосиликон на халяву!

Post by Shaos »

Shaos wrote:
Shaos wrote:Всё работает, кроме C-гейта что внизу схемы :(

Написал программку для встроенного проца - всё работает как надо, включая C-гейт :mrgreen:
Под спойлером текст программки:

 blink_test.c

Code: Select all

#include <defs.h>
#include <stub.h>
void println(){putchar('\n');}
void print_bin(int byte)
{
  int i;
  for(i=7;i>=0;i--)
  {
    if(byte&(1<<i)) putchar('1');
    else putchar('0');
    if(i==4) putchar(' ');
  }
}

// --------------------------------------------------------
// Firmware routines
// --------------------------------------------------------

void configure_io()
{

//  ======= Useful GPIO mode values =============

//      GPIO_MODE_MGMT_STD_INPUT_NOPULL
//      GPIO_MODE_MGMT_STD_INPUT_PULLDOWN
//      GPIO_MODE_MGMT_STD_INPUT_PULLUP
//      GPIO_MODE_MGMT_STD_OUTPUT
//      GPIO_MODE_MGMT_STD_BIDIRECTIONAL
//      GPIO_MODE_MGMT_STD_ANALOG

//      GPIO_MODE_USER_STD_INPUT_NOPULL
//      GPIO_MODE_USER_STD_INPUT_PULLDOWN
//      GPIO_MODE_USER_STD_INPUT_PULLUP
//      GPIO_MODE_USER_STD_OUTPUT
//      GPIO_MODE_USER_STD_BIDIRECTIONAL
//      GPIO_MODE_USER_STD_ANALOG

#define GPIO_MODE_MGMT_CONTROLLED_IO 0x00F
#define GPIO_MODE_USER_CONTROLLED_IO 0x00E

//  ======= set each IO to the desired configuration =============

    //  GPIO 0 is turned off to prevent toggling the debug pin; For debug, make this an output and
    //  drive it externally to ground.

    reg_mprj_io_0 = GPIO_MODE_MGMT_STD_INPUT_NOPULL;

    // Changing configuration for IO[1-4] will interfere with programming flash. if you change them,
    // You may need to hold reset while powering up the board and initiating flash to keep the process
    // configuring these IO from their default values.

    reg_mprj_io_1 = GPIO_MODE_MGMT_STD_OUTPUT;
    reg_mprj_io_2 = GPIO_MODE_MGMT_STD_INPUT_NOPULL;
    reg_mprj_io_3 = GPIO_MODE_MGMT_STD_INPUT_NOPULL;
    reg_mprj_io_4 = GPIO_MODE_MGMT_STD_INPUT_NOPULL;

    // -------------------------------------------

    reg_mprj_io_5 = GPIO_MODE_MGMT_STD_INPUT_NOPULL;     // UART Rx
    reg_mprj_io_6 = GPIO_MODE_MGMT_STD_OUTPUT;           // UART Tx
    reg_mprj_io_7 = GPIO_MODE_MGMT_STD_OUTPUT;
// user inputs (tiny_silicon_1)
    reg_mprj_io_8 = GPIO_MODE_MGMT_CONTROLLED_IO;
    reg_mprj_io_9 = GPIO_MODE_MGMT_CONTROLLED_IO;
    reg_mprj_io_10 = GPIO_MODE_MGMT_CONTROLLED_IO;
    reg_mprj_io_11 = GPIO_MODE_MGMT_CONTROLLED_IO;
    reg_mprj_io_12 = GPIO_MODE_MGMT_CONTROLLED_IO;
    reg_mprj_io_13 = GPIO_MODE_MGMT_CONTROLLED_IO;
    reg_mprj_io_14 = GPIO_MODE_MGMT_CONTROLLED_IO;
    reg_mprj_io_15 = GPIO_MODE_MGMT_CONTROLLED_IO;
// user outputs (tiny_silicon_1)
    reg_mprj_io_16 = GPIO_MODE_USER_CONTROLLED_IO;
    reg_mprj_io_17 = GPIO_MODE_USER_CONTROLLED_IO;
    reg_mprj_io_18 = GPIO_MODE_USER_CONTROLLED_IO;
    reg_mprj_io_19 = GPIO_MODE_USER_CONTROLLED_IO;
    reg_mprj_io_20 = GPIO_MODE_USER_CONTROLLED_IO;
    reg_mprj_io_21 = GPIO_MODE_USER_CONTROLLED_IO;
    reg_mprj_io_22 = GPIO_MODE_USER_CONTROLLED_IO;
    reg_mprj_io_23 = GPIO_MODE_USER_CONTROLLED_IO;

    reg_mprj_io_24 = GPIO_MODE_USER_STD_OUTPUT;
    reg_mprj_io_25 = GPIO_MODE_USER_STD_OUTPUT;
    reg_mprj_io_26 = GPIO_MODE_USER_STD_OUTPUT;
    reg_mprj_io_27 = GPIO_MODE_USER_STD_OUTPUT;
    reg_mprj_io_28 = GPIO_MODE_USER_STD_OUTPUT;
    reg_mprj_io_29 = GPIO_MODE_USER_STD_OUTPUT;
    reg_mprj_io_30 = GPIO_MODE_USER_STD_OUTPUT;
    reg_mprj_io_31 = GPIO_MODE_USER_STD_OUTPUT;
    reg_mprj_io_32 = GPIO_MODE_USER_STD_OUTPUT;
    reg_mprj_io_33 = GPIO_MODE_USER_STD_OUTPUT;
    reg_mprj_io_34 = GPIO_MODE_USER_STD_OUTPUT;
    reg_mprj_io_35 = GPIO_MODE_USER_STD_OUTPUT;
    reg_mprj_io_36 = GPIO_MODE_USER_STD_OUTPUT;
    reg_mprj_io_37 = GPIO_MODE_USER_STD_OUTPUT;

#if 1
    // Initiate the serial transfer to configure IO
    reg_mprj_xfer = 1;
    while (reg_mprj_xfer == 1);
#endif
}

void delay(const int d)
{

    /* Configure timer for a single-shot countdown */
	reg_timer0_config = 0;
	reg_timer0_data = d;
    reg_timer0_config = 1;

    // Loop, waiting for value to reach zero
   reg_timer0_update = 1;  // latch current value
   while (reg_timer0_value > 0) {
           reg_timer0_update = 1;
   }

}

// inputs for tiny_silicon_1

#define CLK   0x01
#define DATA  0x02
#define CLK2  0x04
#define SET   0x08
#define RESET 0x10
#define NAND1 0x20
#define NAND2 0x40
#define DATA2 0x80

int testvec[] = {
// testing D-trigger
0,
CLK,
0,
DATA,
DATA|CLK,
DATA,
0,
CLK,
0,
DATA,
DATA|CLK,
DATA,
// testing D-trigger with SET/RESET
0,
CLK2,
0,
DATA,
DATA|CLK2,
DATA,
0,
CLK2,
0,
DATA,
DATA|CLK2,
DATA,
DATA|RESET,
DATA,
0,
SET,
0,
// testing RS-trigger built out of NAND-gates
NAND1|NAND2,
NAND1,
NAND1|NAND2,
NAND2,
NAND1|NAND2,
// testing C-gate
NAND1|NAND2|DATA,
NAND1|NAND2|DATA|DATA2,
NAND1|NAND2|DATA,
NAND1|NAND2,
NAND1|NAND2|DATA,
NAND1|NAND2|DATA|DATA2,
NAND1|NAND2|DATA2,
NAND1|NAND2,
-1
};


void main()
{
	int i, j, k;

    reg_gpio_mode1 = 1;
    reg_gpio_mode0 = 0;
    reg_gpio_ien = 1;
    reg_gpio_oeb = 0;

    configure_io();

    reg_uart_enable = 1;

    // Configure All LA probes as inputs to the cpu
	reg_la0_oenb = reg_la0_iena = 0x00000000;    // [31:0]
	reg_la1_oenb = reg_la1_iena = 0x00000000;    // [63:32]
	reg_la2_oenb = reg_la2_iena = 0x00000000;    // [95:64]
	reg_la3_oenb = reg_la3_iena = 0x00000000;    // [127:96]

	// write data to la output
    //	reg_la0_data = 0x00;
    //	reg_la1_data = 0x00;
    //	reg_la2_data = 0x00;
    //	reg_la3_data = 0x00;

    // read data from la input
    //	data0 = reg_la0_data;
    //	data1 = reg_la1_data;
    //	data2 = reg_la2_data;
    //	data3 = reg_la3_data;

    print("Hello World !!\n");

	i = j = 0;
	while (1) {

        reg_gpio_out = 1; // OFF
//        reg_mprj_datah = 0x0000002a;
//        reg_mprj_datal = 0xaaaaaaaa;
//	reg_mprj_datal = i<<8;
	reg_mprj_datal = testvec[j++]<<8;
	if(testvec[j]<0) j = 0;

//		delay(50000);
		delay(5000000);

        reg_gpio_out = 0;  // ON
//        reg_mprj_datah = 0x00000015;
//        reg_mprj_datal = 0x55555555;
	k = reg_mprj_datal;

//		delay(50000);
		delay(5000000);

	print("Counter: ");
	print_dec(i++);
	print(" : ");
	print_hex(k,8);
	print(" : ");
	print_bin(k>>8);
	print(" -> ");
	print_bin(k>>16);
	println();
    }


}

и вот её вывод через USB (я только добавил туда расшифровку входов и выходов):

Code: Select all

Hello World !!
CLK -------------------------------.
DATA -----------------------------.|
CLK2 ----------------------------.||
SET ----------------------------,|||
RESET ------------------------. ||||
NAND1 -----------------------.| ||||      RS D2D1
NAND2 ----------------------.|| ||||    _ _  _ _
DATA2 ---------------------.||| ||||    COQQ QQQQ
Counter:  000 : 00b9003d : 0000 0000 -> 1011 1001
Counter:  001 : 003a013d : 0000 0001 -> 0011 1010
Counter:  002 : 00ba003d : 0000 0000 -> 1011 1010
Counter:  003 : 00ba023d : 0000 0010 -> 1011 1010
Counter:  004 : 0039033d : 0000 0011 -> 0011 1001
Counter:  005 : 00b9023d : 0000 0010 -> 1011 1001
Counter:  006 : 00b9003d : 0000 0000 -> 1011 1001
Counter:  007 : 003a013d : 0000 0001 -> 0011 1010
Counter:  008 : 00ba003d : 0000 0000 -> 1011 1010
Counter:  009 : 00ba023d : 0000 0010 -> 1011 1010
Counter:  010 : 0039033d : 0000 0011 -> 0011 1001
Counter:  011 : 00b9023d : 0000 0010 -> 1011 1001
Counter:  012 : 00b9003d : 0000 0000 -> 1011 1001
Counter:  013 : 00b9043d : 0000 0100 -> 1011 1001
Counter:  014 : 00b9003d : 0000 0000 -> 1011 1001
Counter:  015 : 00b9023d : 0000 0010 -> 1011 1001
Counter:  016 : 00b5063d : 0000 0110 -> 1011 0101
Counter:  017 : 00b5023d : 0000 0010 -> 1011 0101
Counter:  018 : 00b5003d : 0000 0000 -> 1011 0101
Counter:  019 : 00b9043d : 0000 0100 -> 1011 1001
Counter:  020 : 00b9003d : 0000 0000 -> 1011 1001
Counter:  021 : 00b9023d : 0000 0010 -> 1011 1001
Counter:  022 : 00b5063d : 0000 0110 -> 1011 0101
Counter:  023 : 00b5023d : 0000 0010 -> 1011 0101
Counter:  024 : 00b9123d : 0001 0010 -> 1011 1001
Counter:  025 : 00b9023d : 0000 0010 -> 1011 1001
Counter:  026 : 00b9003d : 0000 0000 -> 1011 1001
Counter:  027 : 00b5083d : 0000 1000 -> 1011 0101
Counter:  028 : 00b5003d : 0000 0000 -> 1011 0101
Counter:  029 : 0095603d : 0110 0000 -> 1001 0101
Counter:  030 : 00a5203d : 0010 0000 -> 1010 0101
Counter:  031 : 00a5603d : 0110 0000 -> 1010 0101
Counter:  032 : 0095403d : 0100 0000 -> 1001 0101
Counter:  033 : 0095603d : 0110 0000 -> 1001 0101
Counter:  034 : 0095623d : 0110 0010 -> 1001 0101
Counter:  035 : 00d5e23d : 1110 0010 -> 1101 0101
Counter:  036 : 00d5623d : 0110 0010 -> 1101 0101
Counter:  037 : 0095603d : 0110 0000 -> 1001 0101
Counter:  038 : 0095623d : 0110 0010 -> 1001 0101
Counter:  039 : 00d5e23d : 1110 0010 -> 1101 0101
Counter:  040 : 00d5e03d : 1110 0000 -> 1101 0101
Counter:  041 : 0095603d : 0110 0000 -> 1001 0101
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Гуглосиликон на халяву!

Post by Shaos »

В чипах Efabless сделанных по техпроцессу GF180 в качестве микроконтроллера встроена корка VexRiscv, что есть настраиваемая реализация RISC-V (см. https://github.com/SpinalHDL/VexRiscv). Она выполняет код прямо из последовательной SPI-флеши (на девборде стоит 4МБ флеш, способная работать на частотах до 133 МГц) и по слухам в корке есть какой-то маленький кэш инструкций (надо проверить). По памяти раскладка такая (вытащено из h-файла сгенерённого построителем корки, т.е. должно быть корректно):

Code: Select all

VEXRISCV_DEBUG  0xf00f0000 0x100      (256)
SRAM            0x00000000 0x800      (2048)
FLASH           0x10000000 0x1000000  (16777216)
MPRJ            0x30000000 0x10000000 (268435456)
HK              0x26000000 0x300000   (3145728)
CSR             0xf0000000 0x10000    (65536)
FLASH это адресное пространство программ, которое маппится на SPI-флеш (из 16-мегабайтного адресного пространства реально задействовано 4МБ);
SRAM это реально присутствующее в чипе ОЗУ размером всего 2КБ - там располагается память данных;
HK это область портов ввода-вывода, их настройки и чтения-записи;
MPRJ это адресное пространство открываемое внутрь пользовательской логики по шине Wishbone (выше на этой странице есть пример реализации 3 регистров в этом адресном пространстве) - в моих чипах это адресное пространство не используется совсем.

Проц работает на частоте 10 МГц, но есть возможность поставить джампер, который запретит осциллятор девборды и тогда клок надо будет пускать извне через ногу xclk (люди пробовали разгонять чип до 25 МГц).

Последовательный порт на 9600 реализован через FTDI-чип и сразу идёт на USB гнездо (на линуксе оно обнаруживается как /dev/ttyUSB0 и работает через любую терминалку).

Проверил некоторые адреса, а именно первая глобальная переменная, первая переменная в функции main, сама функция main и функция isr (обработчик прерываний):

Code: Select all

global addr 00000008
i addr 000007e4
main addr 10000d64
isr addr 10000178
Получается, что isr тоже сидит в последовательной флеше, а локальные переменные, сидящие в стеке, пододвинуты ближе к концу памяти данных.

P.S. Пытаюсь сравнить скорости исполнения из последовательного флеша и из памяти данных - можно создать глобальный массив 32-битных целых, скопировать туда какую-то функцию и запустить - в результате она будет работать существенно быстрее :)
Например:

Code: Select all

int calc(void)
{
    static int i1,i2;
    reg_timer0_update = 1;  // latch current value
    i1 = reg_timer0_value; // МЕРЯЕМ ОТ СИХ
    global++;
    reg_timer0_update = 1;  // latch current value
    i2 = reg_timer0_value; // ДО СИХ
    return i1-i2;
}
Будучи запущенным из флеша код между сохранениями i1 и i2 (там примерно 12 инструкций) выполняется за 1104 такта, а из памяти данных - только 86 (что тоже многовато).
Если поставить два global++ вместо одного (примерно 15 инструкций), то числа уже 1119 и 98 - получается один инкремент глобальной переменной в ОЗУ занимает 12 тактов, что есть 3 инструкции:

Code: Select all

10000d24:       01002783                lw      a5,16(zero) # 10 <_edata>
10000d28:       00178713                addi    a4,a5,1
10000d2c:       00e02823                sw      a4,16(zero) # 10 <_edata>
Значит одна инструкция запускается тут за 4 такта!
А вот если добавить третий global++ (примерно 18 инструкций), то числа уже станут 2192 и 130 соответственно (уже на 32 такта больше???).
Если убрать global++ вовсе (тогда между замерами станет 9 инструкций), то цифры становятся 1095 и 53.
Так что похоже кэш инструкций там таки есть и он перезаписывается примерно после 16 инструкций:

Code: Select all

 9 : 1095 :  53 : ideal 36 (+17)
12 : 1104 :  86 : ideal 48 (+38)
15 : 1119 :  98 : ideal 60 (+38)
18 : 2192 : 130 : ideal 72 (+58)
P.P.S. Выровнял смещение для скопированной функции в памяти данных так, чтобы было как во флеше (первое сохранение текущего счётчика тактов приходится на начало 64-байтного блока) - теперь стало так (замеры только для ОЗУ):

Code: Select all

 9 :  55 : ideal 36 (+19)
12 :  64 : ideal 48 (+16)
15 :  79 : ideal 60 (+19)
18 : 112 : ideal 72 (+40)
Ещё интересное наблюдение - 3 nop-a занимают меньше тактов (на 6 меньше), чем эти 3 инструкции:

Code: Select all

10000d24:       01002783                lw      a5,16(zero) # 10 <_edata>
10000d28:       00178713                addi    a4,a5,1
10000d2c:       00e02823                sw      a4,16(zero) # 10 <_edata>
Хотя казалось бы, это RISC - всё должно быть одинаково (если это не передача управления), тем более NOP это на самом деле ADDI R0,R0,0 (хотя тут есть store инструкция - комнда sw, которая например в моей реализации была чуть дольше остальных)...

P.P.P.S. Вот исходники версии Caravel-проца, что ставится в GF180: https://github.com/efabless/caravel_mgmt_soc_gf180mcu/tree/main
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Гуглосиликон на халяву!

Post by Shaos »

Вообще два раза подряд global++ без оптимизации компилируется вот так:

Code: Select all

       01002783                lw      a5,16(zero) # 10 <_edata>
       00178713                addi    a4,a5,1
       00e02823                sw      a4,16(zero) # 10 <_edata>
       01002783                lw      a5,16(zero) # 10 <_edata>
       00178713                addi    a4,a5,1
       00e02823                sw      a4,16(zero) # 10 <_edata>
т.е. сразу после сохранения переменной в памяти идёт чтение переменной из этой памяти, что может вызывать проблемы у RISC-процессоров - возможно корка ждёт, когда переменная будет записана прежде чем её прочитает, а может и не ждёт...

По тактам значит получается так:

Code: Select all

 # : FLASH        :  SRAM
----------------------------------
 9 : 1095         :  55
12 : 1104 (+9)    :  64 (+9)
15 : 1119 (+15)   :  79 (+15)
18 : 2192 (+1073) : 112 (+33)
Как можно видеть переход от 9 к 12 и потом к 15 инструкциям отличается на одинаковое кол-во тактов для флаша и для срама, а вот зашкал за 16 сильно длиннее у флеша т.к. там идёт заполнение кеша инструкций из SPI-флеша (а может глубина кеша 8, а не 16 и поэтому при 9 сразу много?).

P.S. Потестил добавление NOP-ов по одному:

Code: Select all

 9 : 55
10 : 52  (-3)
11 : 57  (+5)
12 : 58  (+1)
13 : 59  (+1)
14 : 60  (+1)
15 : 77  (+17)
16 : 78  (+1)
17 : 83  (+5)
18 : 80  (-3)
19 : 85  (+5)
20 : 86  (+1)
21 : 87  (+1)
22 : 88  (+1)
23 : 105 (+17)
Тут отчётливо видно, что кэш инструкций вмещает в себя 8 команд.

P.P.S. Вот ещё замеры LW и SW:

Code: Select all

LWs:

 9 : 55
10 : 55 (0)
11 : 60 (+5)
12 : 62 (+2)
13 : 65 (+3)
14 : 68 (+3)
15 : 71 (+3)
16 : 92 (+21)
17 : 99 (+7)
18 : 98 (-1)
19 : 103 (+5)
20 : 105 (+2)

SWs:

 9 : 55
10 : 55 (0)
11 : 59 (+4)
12 : 60 (+1)
13 : 63 (+3)
14 : 66 (+3)
15 : 69 (+3)
16 : 90 (+21)
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Гуглосиликон на халяву!

Post by Shaos »

Думаю сгенерить NTSC-сигнал программно на Caravel

На 5 МГц 19 лет назад я так времянки раскладывал:

Code: Select all

Frame (in lines) 262:
20-sync 24-preframe 192-frame 26-postframe
Line (in ticks) 318:
24-low 30-high 256-signal 8-high
Для 10 МГц можно поточнее цифры иметь:
- NTSC строка имеет длину 63.5us, что превращается в 635 тактов;
- видимая часть строки занимает 52.6us, что есть 526 тактов;
- строчный синхроимпульс 4.7us это 47 тактов.

Можно попробовать сделать так:
47-low 124-high 384-signal 80-high
(полезный сигнал сужен, чтобы получить 32 клетки по 12 тактов каждая)

Для точного позиционирования можно использовать timer0 в Periodic mode:
https://caravel-mgmt-soc-litex.readthedocs.io/en/latest/generated/timer0.html
Когда счёт идёт вниз от введённого значения и когда счётчик достигает 0, таймер снова взводится начальным значением и считает дальше - считать будем в пределах строки от 634 до нуля:
- если новое число больше предыдущего (т.е. произошла перезагрузка счётчика), то устанавливаем синхру в 0;
- если число стало меньше 587, то устанавливаем синхру в 1;
- если число стало меньше 463, то начинаем вывод 384 пикселов (32 клетки по 12 тактов каждая);
- далее ждём условия перезагрузки счётчика (см. пункт первый).

Вывод 32 клеток кодом из ОЗУ:

Code: Select all

    asm volatile(
    "nop\n"
    "nop\n"
    "nop\n"
    "lw      a4,8(zero)\n"// ...30
    "lui     a5,0x26000\n"// ...34
    "addi    a5,a5,12\n"  // ...38
    "li      a2,32\n"     // ...3C <<< N= 1,  2,  3,  4,  5,  6,  7,  8 ... 32
    "loop: sw a4,0(a5)\n" // ...40
    "slli    a4,a4,0x1\n" // ...44
    "addi    a2,a2,-1\n"  // ...48
    "bnez    a2,loop\n"   // ...4C ----> 104 115 127 139 151 163 175 187...475
    );                                       +11 +12 +12 +12 +12 +12 +12...91+N*12
В данном случае сдвигается влево 32-битное целое, взятое по адресу 8 - вывод каждого бита занимает ровно 12 тактов.
Так как на предустановку уходит какое-то время, то начинать это делать надо не на 463м такте, а раньше...
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Гуглосиликон на халяву!

Post by Shaos »

Пытаюсь разобраться в том какой всё-таки размер у кеша инструкций в этой версии VexRiscv.

Тот же код, что выше (плюс кое-какой набор инструкций, используемый для замера продолжительности работы):

Code: Select all

// ...34 f00057b7                lui     a5,0xf0005
// ...38 00c78793                addi    a5,a5,12 # f000500c <_fdata_rom+0xe0003cb4>
// ...3C 00100713                li      a4,1
// ...40 00e7a023                sw      a4,0(a5) <<<<<<<<<<<< МЕРЯЕМ ОТ СИХ
// ...44 f00057b7                lui     a5,0xf0005
// ...48 01078793                addi    a5,a5,16 # f0005010 <_fdata_rom+0xe0003cb8>
// ...4C 0007a783                lw      a5,0(a5)
// ...50 00078713                mv      a4,a5
// ...54 00e02823                sw      a4,16(zero) # 10 <i1.2347>

    asm volatile(
    "nop\n"               // ...58
    "nop\n"               // ...5C
    "nop\n"               // ...60
    "lw      a4,8(zero)\n"// ...64
    "lui     a5,0x26000\n"// ...58
    "addi    a5,a5,12\n"  // ...6C
    "li      a2,32\n"     // ...70 <<< N= 1,  2,  3,  4,  5,  6,  7,  8 ... 32
    "loop: sw a4,0(a5)\n" // ...74
    "slli    a4,a4,0x1\n" // ...78
    "addi    a2,a2,-1\n"  // ...7C
    "bnez    a2,loop\n"   // ...80 ----> 104 115 127 139 151 163 175 187...475
    );                                       +11 +12 +12 +12 +12 +12 +12...91+N*12

// ...84 f00057b7                lui     a5,0xf0005
// ...88 00c78793                addi    a5,a5,12 # f000500c <_fdata_rom+0xe0003cb4>
// ...8C 00100713                li      a4,1
// ...90 00e7a023                sw      a4,0(a5) <<<<<<<< ДО СИХ...
при любом N выполняется дольше на 4 такта, чем вот такой:

Code: Select all

// ...34 f00057b7                lui     a5,0xf0005
// ...38 00c78793                addi    a5,a5,12 # f000500c <_fdata_rom+0xe0003cb4>
// ...3C 00100713                li      a4,1
// ...40 00e7a023                sw      a4,0(a5) <<<<<<<<<<<< МЕРЯЕМ ОТ СИХ
// ...44 f00057b7                lui     a5,0xf0005
// ...48 01078793                addi    a5,a5,16 # f0005010 <_fdata_rom+0xe0003cb8>
// ...4C 0007a783                lw      a5,0(a5)
// ...50 00078713                mv      a4,a5
// ...54 00e02823                sw      a4,16(zero) # 10 <i1.2347>

    asm volatile(
    "nop\n"               // ...58
    "nop\n"               // ...5C
    "nop\n"               // ...60
    "nop\n"               // ...64
    "nop\n"               // ...68
    "nop\n"               // ...6C
    "lw      a4,8(zero)\n"// ...70
    "lui     a5,0x26000\n"// ...74
    "addi    a5,a5,12\n"  // ...78
    "li      a2,32\n"     // ...7C <<< N= 1,  2,  3,  4 ... 32
    "loop: sw a4,0(a5)\n" // ...80
    "slli    a4,a4,0x1\n" // ...84
    "addi    a2,a2,-1\n"  // ...88
    "bnez    a2,loop\n"   // ...8C ---->  99 111 123 135...471 (-4)
    );                                       +12 +12 +12...87+N*12

// ...90 f00057b7                lui     a5,0xf0005
// ...94 00c78793                addi    a5,a5,12 # f000500c <_fdata_rom+0xe0003cb4>
// ...98 00100713                li      a4,1
// ...9C 00e7a023                sw      a4,0(a5) <<<<<<<< ДО СИХ...
И это нее смотря на то, что в последнем на ТРИ NOP-а больше!

P.S. А вообще при разном количестве нопов в начале асмового блока получаеются вот такие времена (при N=32):

Code: Select all

0 -> 466
1 -> 467
2 -> 469
3 -> 475 (первоначальный вариант в предыдущем сообщении)
4 -> 481
5 -> 483
6 -> 471 (эта самая непонятка)
7 -> 492
8 -> 494
Как можно видеть между 0 и 8 разница 28 тактов, что вполне соотносится с тестом на голимые нопы (9 инструкций обёртка плюс N нопов):

Code: Select all

 9 : 55
10 : 52  (-3)
11 : 57  (+5)
12 : 58  (+1)
13 : 59  (+1)
14 : 60  (+1)
15 : 77  (+17)
16 : 78  (+1)
17 : 83  (+5)
18 : 80  (-3)
19 : 85  (+5)
20 : 86  (+1)
21 : 87  (+1)
22 : 88  (+1)
23 : 105 (+17)
(при любом сдвиге 8 нопов подряд занимают 28 тактов)
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Гуглосиликон на халяву!

Post by Shaos »

Короче выходит, что из памяти действительно читается по 8 инструкций, однако при прохождении этих 8 инструкций будет вычитано следующие 8 ( без очистки предыдущих 8 ) и если код крутится в пределах этих 16 инструкций (64 байта), то никаких новых вычиток из памяти производится не будет!...
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Гуглосиликон на халяву!

Post by Shaos »

Покопался в верилоговских сырках проца:
https://github.com/efabless/caravel_mgmt_soc_gf180mcu/blob/main/verilog/rtl/VexRiscv_MinDebugCache.v
Размер кеша там точно 16 слов:

Code: Select all

   (* ram_style = "block" *) reg [31:0] banks_0 [0:15];
Однако заполняет он их хитро:

Code: Select all

 wire       [3:0]    lineLoader_write_data_0_payload_address;
 ...
       banks_0[lineLoader_write_data_0_payload_address] <= lineLoader_write_data_0_payload_data;
 ...
   assign lineLoader_write_data_0_payload_address = {lineLoader_address[5 : 5],lineLoader_wordIndex};
Получается, что 5й бит адреса вычитанной последовательности слов управляет тем в какую половинку кэша инструкций будут писаться вычитываемые 8 слов:

Code: Select all

   (* keep , syn_keep *) reg        [31:0]   lineLoader_address /* synthesis syn_keep = 1 */ ;
 ...
   (* keep , syn_keep *) reg        [2:0]    lineLoader_wordIndex /* synthesis syn_keep = 1 */
Соответственно в кеше инструкций всегда сидят 16 инструкций подряд, однако половинки кеша перемежаются - следующие 8 инструкций затирают позапредыдущие 8 инструкций, оставляя предыдущие 8 инструкций - вобщем как-то так...
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Гуглосиликон на халяву!

Post by Shaos »

Shaos wrote:Дочка даже прикручивается винтиком :)

Image
Пишут вот такой разъёмчик тут стоит:

https://www.lcsc.com/product-detail/Card-Edge-Connectors_TE-Connectivity-2199230-4_C2977809.html

Думаю понаделать своих платок (попроще) чтобы воткнуть туда все 20 доче-платок, что у меня есть :mrgreen:

А потом может дойду и до распаивания собственных доче-платок, чтобы припаять туда 200+ чипов Caravel, что у меня есть :roll:
Я тут за главного - если что шлите мыло на me собака shaos точка net