Skip to content

Commit

Permalink
Add ability to use the clock net for PLL signals (#139)
Browse files Browse the repository at this point in the history
* Add ability to use the clock net for PLL signals

The nextpnr can now use the clock network to deliver PLL outputs if it sees fit.

On the apicula chip base side, all four outputs can be connected to the
clock network, but the nextpnr currently has a limit of 3 networks, if
I'm not mistaken. This is not being touched for the time being.

In the process of experimentation, the functions of the many internal
wires of the large central clock MUX have been discovered and these are
reflected in the names.

An example of using the PLL to form a picture on a 4.3" LCD screen is added.

! This commit uses the existing clock network processing logic and does
not require any changes to the nextpnr, i.e. no new information about
the big MUX device will be applied.

Signed-off-by: YRabbit <[email protected]>

* Delete accidentally added temporary files

Signed-off-by: YRabbit <[email protected]>

Signed-off-by: YRabbit <[email protected]>
  • Loading branch information
yrabbit authored Dec 17, 2022
1 parent 0786a9d commit 5646882
Show file tree
Hide file tree
Showing 5 changed files with 315 additions and 3 deletions.
21 changes: 21 additions & 0 deletions apycula/chipdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,25 @@ def fse_fill_logic_tables(dev, fse):
for f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, *fuses in fse[ttyp]['longval'][ltable]:
table[(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15)] = {fuse.fuse_lookup(fse, ttyp, f) for f in unpad(fuses)}

_pll_loc = {
'GW1N-1':
{'TRPLL0CLK0': (0, 17, 'F4'), 'TRPLL0CLK1': (0, 17, 'F5'),
'TRPLL0CLK2': (0, 17, 'F6'), 'TRPLL0CLK3': (0, 17, 'F7'), },
'GW1NZ-1':
{'TRPLL0CLK0': (0, 17, 'F4'), 'TRPLL0CLK1': (0, 17, 'F5'),
'TRPLL0CLK2': (0, 17, 'F6'), 'TRPLL0CLK3': (0, 17, 'F7'), },
}
def fse_create_pll_clock_aliases(db, device):
# we know exactly where the PLL is and therefore know which aliases to create
for row in range(db.rows):
for col in range(db.cols):
for w_dst, w_srcs in db.grid[row][col].clock_pips.items():
for w_src in w_srcs.keys():
# XXX
if device in {'GW1N-1', 'GW1NZ-1'}:
if w_src in _pll_loc[device].keys():
db.aliases[(row, col, w_src)] = _pll_loc[device][w_src]

def from_fse(device, fse):
dev = Device()
ttypes = {t for row in fse['header']['grid'][61] for t in row}
Expand All @@ -432,12 +451,14 @@ def from_fse(device, fse):
tile.bels = fse_luts(fse, ttyp)
if 51 in fse[ttyp]['shortval']:
tile.bels = fse_osc(device, fse, ttyp)
# XXX GW1N(Z)-1 for now
if ttyp in [88, 89]:
tile.bels = fse_pll(device, fse, ttyp)
tiles[ttyp] = tile

fse_fill_logic_tables(dev, fse)
dev.grid = [[tiles[ttyp] for ttyp in row] for row in fse['header']['grid'][61]]
fse_create_pll_clock_aliases(dev, device)
return dev

# get fuses for attr/val set using short/longval table
Expand Down
56 changes: 55 additions & 1 deletion apycula/wirenames.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,60 @@
clknames.update({n: f"SPINE{n}" for n in range(32)})
clknames.update({n: f"LWT{n - 32}" for n in range(32, 40)})
clknames.update({n: f"LWB{n - 40}" for n in range(40, 48)})
clknames.update({n: f"UNK{n}" for n in range(48, 261)})
# Apparently the names of the 8 primary clock wires comprise the quadrant
# number and the number of the actual clock wire: P34 stands for primary clock
# #4, 3rd quadrant. The quadrants are numbered counterclockwise:
# 2 1
# center
# 3 4
# in addition, chips with two quadrants have quadrant numbers 3 and 4, not 1
# and 2 as you might expect.
# Wires 6 and 7 are the outputs of the dynamic 4-input MUX, the assumed
# numbers of these inputs are listed below:
clknames.update({
48: 'P16A', 49: 'P16B', 50: 'P16C', 51: 'P16D',
52: 'P17A', 53: 'P17B', 54: 'P17C', 55: 'P17D',
56: 'P26A', 57: 'P26B', 58: 'P26C', 59: 'P26D',
60: 'P27A', 61: 'P27B', 62: 'P27C', 63: 'P27D',
64: 'P36A', 65: 'P36B', 66: 'P36C', 67: 'P36D',
68: 'P37A', 69: 'P37B', 70: 'P37C', 71: 'P37D',
72: 'P46A', 73: 'P46B', 74: 'P46C', 75: 'P46D',
76: 'P47A', 77: 'P47B', 78: 'P47C', 79: 'P47D'
})
clknames[80] = 'VSS'
# each PLL has 4 delay-critical outputs (clkout, clkoutp, clkoutd, clkoutd3),
# their numbers are listed here, the names indicate the possible location of
# the PLL (Top Left etc):
clknames.update({
81: 'TLPLL0CLK0', 82: 'TLPLL0CLK1', 83: 'TLPLL0CLK2', 84: 'TLPLL0CLK3',
85: 'TLPLL1CLK0', 86: 'TLPLL1CLK1', 87: 'TLPLL1CLK2', 88: 'TLPLL1CLK3',
89: 'BLPLL0CLK0', 90: 'BLPLL0CLK1', 91: 'BLPLL0CLK2', 92: 'BLPLL0CLK3',
93: 'TRPLL0CLK0', 94: 'TRPLL0CLK1', 95: 'TRPLL0CLK2', 96: 'TRPLL0CLK3',
97: 'TRPLL1CLK0', 98: 'TRPLL1CLK1', 99: 'TRPLL1CLK2', 100: 'TRPLL1CLK3',
101: 'BRPLL0CLK0', 102: 'BRPLL0CLK1', 103: 'BRPLL0CLK2', 104: 'BRPLL0CLK3',
})
clknames.update({n: f"UNK{n}" for n in range(105, 121)})
# These are the external clock pins, one on each side
clknames.update({
121: 'PCLKT0', 122: 'PCLKT1', 123: 'PCLKB0', 124: 'PCLKB1',
125: 'PCLKL0', 126: 'PCLKL1', 127: 'PCLKR0', 128: 'PCLKR1',
})
clknames.update({n: f"UNK{n}" for n in range(129, 153)})
clknames[153] = 'VCC'
clknames.update({n: f"UNK{n}" for n in range(154, 186)})
# These wires are a mystery, they are a copy of P10-P15 etc, there is no reason
# to have another number for the output, but it is these numbers that are
# listed in tables 38, although the internal routes are routed to the
# originals.
# In general they are needed and the letter A is added to make the names
# different.
clknames.update({
186: 'P10A', 187: 'P11A', 188: 'P12A', 189: 'P13A', 190: 'P14A', 191: 'P15A',
192: 'P20A', 193: 'P21A', 194: 'P22A', 195: 'P23A', 196: 'P24A', 197: 'P25A',
198: 'P30A', 199: 'P31A', 200: 'P32A', 201: 'P33A', 202: 'P34A', 203: 'P35A',
204: 'P40A', 205: 'P41A', 206: 'P42A', 207: 'P43A', 208: 'P44A', 209: 'P45A',
})

clknames.update({n: f"UNK{n}" for n in range(210, 261)})

clknumbers = {v: k for k, v in clknames.items()}
9 changes: 7 additions & 2 deletions examples/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ all: attosoc-tec0117.fs nanolcd-tangnano.fs blinky-tec0117.fs blinky-runber.fs \
globals_all \
pll-52-tangnano.fs pll-80-tangnano.fs \
pll-54-tangnano1k.fs pll-81-tangnano1k.fs \
pll-dyn-tangnano.fs pll-dyn-tangnano1k.fs
pll-dyn-tangnano.fs pll-dyn-tangnano1k.fs \
pll-nanolcd-tangnano.fs

unpacked: attosoc-tec0117-unpacked.v nanolcd-tangnano-unpacked.v blinky-tec0117-unpacked.v blinky-runber-unpacked.v \
blinky-tangnano-unpacked.v blinky-honeycomb-unpacked.v shift-tec0117-unpacked.v shift-runber-unpacked.v \
Expand All @@ -46,7 +47,8 @@ unpacked: attosoc-tec0117-unpacked.v nanolcd-tangnano-unpacked.v blinky-tec0117-
globals_unpacked \
pll-52-tangnano-unpacked.v pll-80-tangnano-unpacked.v \
pll-54-tangnano1k-unpacked.v pll-81-tangnano1k-unpacked.v \
pll-dyn-tangnano-unpacked.v pll-dyn-tangnano1k-unpacked.v
pll-dyn-tangnano-unpacked.v pll-dyn-tangnano1k-unpacked.v \
pll-nanolcd-tangnano-unpacked.v

clean: globals_clean
rm -f *.json *.fs *-unpacked.v
Expand Down Expand Up @@ -113,6 +115,9 @@ tonegen-tec0117-synth.json: tonegen/top.v tonegen/sddac.v tonegen/cordic.v
nanolcd-tangnano-synth.json: nanolcd/TOP.v nanolcd/VGAMod.v
$(YOSYS) -p "read_verilog $^; synth_gowin -json $@"

pll-nanolcd-tangnano-synth.json: pll-nanolcd/TOP.v pll-nanolcd/VGAMod.v
$(YOSYS) -p "read_verilog $^; synth_gowin -noalu -json $@"

%-tec0117-synth.json: %.v
$(YOSYS) -D LEDS_NR=8 -D OSC_TYPE_OSC -p "read_verilog $^; synth_gowin -json $@"

Expand Down
109 changes: 109 additions & 0 deletions examples/pll-nanolcd/TOP.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
(* top *)
module TOP
(
input rst,
input clk,

output LCD_CLK,
output LCD_HYNC,
output LCD_SYNC,
output LCD_DEN,
output [4:0] LCD_R,
output [5:0] LCD_G,
output [4:0] LCD_B,

output [2:0] led

);

wire CLK_SYS;
wire CLK_PIX;
wire LED_R;
wire LED_G;
wire LED_B;

/* //使用内部时钟
Gowin_OSC chip_osc(
.oscout(oscout_o) //output oscout
);
*/
rPLL pll(
.CLKOUT(CLK_SYS), // 90MHz
.CLKIN(clk),
.CLKOUTD(CLK_PIX),
.CLKFB(GND),
.FBDSEL({GND,GND,GND,GND,GND,GND}),
.IDSEL({GND,GND,GND,GND,GND,GND}),
.ODSEL({GND,GND,GND,GND,GND,GND}),
.DUTYDA({GND,GND,GND,GND}),
.PSDA({GND,GND,GND,GND}),
.FDLY({GND,GND,GND,GND}),
);
defparam pll.DEVICE = "GW1N-1";
defparam pll.FCLKIN = "24";
defparam pll.FBDIV_SEL = 29;
defparam pll.IDIV_SEL = 7;
defparam pll.ODIV_SEL = 8; // 90MHz sys clock
defparam pll.CLKFB_SEL="internal";
defparam pll.CLKOUTD3_SRC="CLKOUT";
defparam pll.CLKOUTD_BYPASS="false";
defparam pll.CLKOUTD_SRC="CLKOUT";
defparam pll.CLKOUTP_BYPASS="false";
defparam pll.CLKOUTP_DLY_STEP=0;
defparam pll.CLKOUTP_FT_DIR=1'b1;
defparam pll.CLKOUT_BYPASS="false";
defparam pll.CLKOUT_DLY_STEP=0;
defparam pll.CLKOUT_FT_DIR=1'b1;
defparam pll.DEVICE="GW1N-1";
defparam pll.DUTYDA_SEL="1000";
defparam pll.DYN_DA_EN="false";
defparam pll.DYN_FBDIV_SEL="false";
defparam pll.DYN_IDIV_SEL="false";
defparam pll.DYN_ODIV_SEL="false";
defparam pll.DYN_SDIV_SEL=10; // 90MHz / 10 = 9MHz --- pixel clock
defparam pll.PSDA_SEL="0000";

assign led[0] = LED_R;
assign led[1] = LED_G;
assign led[2] = LED_B;

VGAMod D1
(
.CLK ( CLK_SYS ),
.nRST ( rst ),

.PixelClk ( CLK_PIX ),
.LCD_DE ( LCD_DEN ),
.LCD_HSYNC ( LCD_HYNC ),
.LCD_VSYNC ( LCD_SYNC ),

.LCD_B ( LCD_B ),
.LCD_G ( LCD_G ),
.LCD_R ( LCD_R )
);

assign LCD_CLK = CLK_PIX;

//RGB LED TEST
reg [31:0] Count;
reg [1:0] rgb_data;
always @( posedge CLK_SYS or negedge rst )
begin
if( !rst )
begin
Count <= 32'd0;
rgb_data <= 2'b00;
end
else if ( Count == 12000000 )
begin
Count <= 4'b0;
rgb_data <= rgb_data + 1'b1;
end
else
Count <= Count + 1'b1;
end
assign LED_R = ~(rgb_data == 2'b01);
assign LED_G = ~(rgb_data == 2'b10);
assign LED_B = ~(rgb_data == 2'b11);

endmodule
123 changes: 123 additions & 0 deletions examples/pll-nanolcd/VGAMod.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
module VGAMod
(
input CLK,
input nRST,

input PixelClk,

output LCD_DE,
output LCD_HSYNC,
output LCD_VSYNC,

output [4:0] LCD_B,
output [5:0] LCD_G,
output [4:0] LCD_R
);

reg [15:0] PixelCount;
reg [15:0] LineCount;

//pulse include in back pulse; t=pulse, sync act; t=bp, data act; t=bp+height, data end

/* 480x272 4.3" LCD with SC7283 driver, pixel freq = 9MHz */
localparam V_BackPorch = 16'd12;
localparam V_Pulse = 16'd4;
localparam HightPixel = 16'd272;
localparam V_FrontPorch= 16'd8;

localparam H_BackPorch = 16'd43;
localparam H_Pulse = 16'd4;
localparam WidthPixel = 16'd480;
localparam H_FrontPorch= 16'd8;

/*localparam V_BackPorch = 16'd12;
localparam V_Pulse = 16'd11;
localparam HightPixel = 16'd272;
localparam V_FrontPorch= 16'd8;
localparam H_BackPorch = 16'd50;
localparam H_Pulse = 16'd10;
localparam WidthPixel = 16'd480;
localparam H_FrontPorch= 16'd8; */
/*
localparam V_BackPorch = 16'd0; //6
localparam V_Pulse = 16'd5;
localparam HightPixel = 16'd480;
localparam V_FrontPorch= 16'd45; //62
localparam H_BackPorch = 16'd182; //NOTE: 高像素时钟时,增加这里的延迟,方便K210加入中断
localparam H_Pulse = 16'd1;
localparam WidthPixel = 16'd800;
localparam H_FrontPorch= 16'd210;
*/

localparam PixelForHS = WidthPixel + H_BackPorch + H_FrontPorch;
localparam LineForVS = HightPixel + V_BackPorch + V_FrontPorch;

always @( posedge PixelClk or negedge nRST )begin
if( !nRST ) begin
LineCount <= 16'b0;
PixelCount <= 16'b0;
end
else if( PixelCount == PixelForHS ) begin
PixelCount <= 16'b0;
LineCount <= LineCount + 1'b1;
end
else if( LineCount == LineForVS ) begin
LineCount <= 16'b0;
PixelCount <= 16'b0;
end
else begin
PixelCount <= PixelCount + 1'b1;
end
end

reg [9:0] Data_R;
reg [9:0] Data_G;
reg [9:0] Data_B;

always @( posedge PixelClk or negedge nRST )begin
if( !nRST ) begin
Data_R <= 9'b0;
Data_G <= 9'b0;
Data_B <= 9'b0;
end
else begin
end
end

//注意这里HSYNC和VSYNC负极性
assign LCD_HSYNC = (( PixelCount >= H_Pulse)&&( PixelCount <= (PixelForHS-H_FrontPorch))) ? 1'b0 : 1'b1;
//assign LCD_VSYNC = ((( LineCount >= 0 )&&( LineCount <= (V_Pulse-1) )) ) ? 1'b1 : 1'b0; //这里不减一的话,图片底部会往下拖尾?
assign LCD_VSYNC = ((( LineCount >= V_Pulse )&&( LineCount <= (LineForVS-0) )) ) ? 1'b0 : 1'b1;
//assign FIFO_RST = (( PixelCount ==0)) ? 1'b1 : 1'b0; //留给主机H_BackPorch的时间进入中断,发送数据

assign LCD_DE = ( ( PixelCount >= H_BackPorch )&&
( PixelCount <= PixelForHS-H_FrontPorch ) &&
( LineCount >= V_BackPorch ) &&
( LineCount <= LineForVS-V_FrontPorch-1 )) ? 1'b1 : 1'b0;
//这里不减一,会抖动

assign LCD_R = (PixelCount<110)? 5'b00000 :
(PixelCount<132 ? 5'b00001 :
(PixelCount<154 ? 5'b00010 :
(PixelCount<176 ? 5'b00100 :
(PixelCount<198 ? 5'b01000 :
(PixelCount<220 ? 5'b10000 : 5'b00000 )))));

assign LCD_G = (PixelCount<220)? 6'b000000 :
(PixelCount<242 ? 6'b000001 :
(PixelCount<264 ? 6'b000010 :
(PixelCount<286 ? 6'b000100 :
(PixelCount<308 ? 6'b001000 :
(PixelCount<330 ? 6'b010000 :
(PixelCount<352 ? 6'b100000 : 6'b000000 ))))));

assign LCD_B = (PixelCount<352)? 5'b00000 :
(PixelCount<374 ? 5'b00001 :
(PixelCount<396 ? 5'b00010 :
(PixelCount<418 ? 5'b00100 :
(PixelCount<440 ? 5'b01000 :
(PixelCount<462 ? 5'b10000 : 5'b00000 )))));

endmodule

0 comments on commit 5646882

Please sign in to comment.