tridoracpu: clock, mem and top variants for CCGMA1 chip

This commit is contained in:
slederer 2025-02-27 01:41:33 +01:00
parent 91b693979d
commit 2edd5679a1
5 changed files with 419 additions and 5 deletions

1
.gitignore vendored
View file

@ -31,6 +31,7 @@ pcomp/pcomp
pcomp/sasm pcomp/sasm
pcomp/sdis pcomp/sdis
tridoraemu/tridoraemu tridoraemu/tridoraemu
tridoracpu/build
**/tridoracpu.cache/ **/tridoracpu.cache/
**/tridoracpu.hw/ **/tridoracpu.hw/
**/tridoracpu.ip_user_files/ **/tridoracpu.ip_user_files/

View file

@ -18,19 +18,20 @@ BITSTREAM = build/$(TOP)_00.cfg.bit
srcs = \ srcs = \
$(SRCDIR)/bram_tdp.v \ $(SRCDIR)/bram_tdp.v \
$(SRCDIR)/dram_bridge.v \
$(SRCDIR)/fifo.v \ $(SRCDIR)/fifo.v \
$(SRCDIR)/irqctrl.v \ $(SRCDIR)/irqctrl.v \
$(SRCDIR)/mem.v \
$(SRCDIR)/palette.v \ $(SRCDIR)/palette.v \
$(SRCDIR)/sdspi.v \ $(SRCDIR)/sdspi.v \
$(SRCDIR)/stackcpu.v \ $(SRCDIR)/stackcpu.v \
$(SRCDIR)/stack.v \ $(SRCDIR)/stack.v \
$(SRCDIR)/top.v \
$(SRCDIR)/uart.v \ $(SRCDIR)/uart.v \
$(SRCDIR)/vgafb.v $(SRCDIR)/vgafb.v
#srcs += $(SRCDIR)/ccgma1_clocks.v # for CCGMA1-EVB
srcs += $(SRCDIR)/cpuclk_ccgm.v $(SRCDIR)/top_ccgm.v $(SRCDIR)/mem_ccgm.v
# for Arty-A7
# src += $(SRCDIR)/cpuclk.v $(SRCDIR)/top.v $(SRCDIR)/mem.v
all: build synth impl all: build synth impl
clean: clean:
@ -49,7 +50,7 @@ $(SYNTHFILE): $(srcs)
$(YOSYS) -ql build/synth.log -p 'read -sv $(srcs); synth_gatemate -top $(TOP) -nomx8 -vlog $(SYNTHFILE)' $(YOSYS) -ql build/synth.log -p 'read -sv $(srcs); synth_gatemate -top $(TOP) -nomx8 -vlog $(SYNTHFILE)'
$(BITSTREAM): $(SYNTHFILE) $(BITSTREAM): $(SYNTHFILE)
$(PNR) -v -i build/$(SYNTHFILE) -o $(TOP) $(PNRFLAGS) >build/$@.log $(PNR) -v -i $(SYNTHFILE) -o build/$(TOP) $(PNRFLAGS) >$@.log
prog: $(BITSTREAM) prog: $(BITSTREAM)
$(OFL) $(OFLFLAGS) --bitstream $(BITSTREAM) $(OFL) $(OFLFLAGS) --bitstream $(BITSTREAM)

View file

@ -0,0 +1,41 @@
`timescale 1ns / 1ps
module cpu_clkgen(
input wire rst,
input wire clk10,
output wire cpuclk,
output wire locked
);
wire usr_pll_lock_stdy;
wire usr_pll_lock;
wire usr_ref_out;
wire clk_nobuf;
assign locked = usr_pll_lock;
CC_PLL #(
.REF_CLK("10.0"),
.OUT_CLK("25.0"),
.LOCK_REQ("1"),
.PERF_MD("SPEED"),
.LOW_JITTER(1),
.CI_FILTER_CONST(2),
.CP_FILTER_CONST(4)
) pll_cpuclk (
.CLK_REF(clk10),
.CLK_FEEDBACK(1'b0),
.USR_CLK_REF(1'b0),
.USR_LOCKED_STDY_RST(1'b0),
.USR_PLL_LOCKED_STDY(usr_pll_lock_stdy),
.USR_PLL_LOCKED(usr_pll_lock),
.CLK0(clk_nobuf),
.CLK_REF_OUT(usr_ref_out)
);
CC_BUFG pll_bufg (
.I(clk_nobuf),
.O(cpuclk)
);
endmodule

View file

@ -0,0 +1,129 @@
`timescale 1ns / 1ps
// 32 bit wide rom with byte addressing (address bits 1-0 are ignored)
module rom32 #(parameter ADDR_WIDTH = 11, DATA_WIDTH = 32)
(
input wire clk,
input wire [ADDR_WIDTH-1:0] addr,
output reg [DATA_WIDTH-1:0] data_out,
input wire read_enable
);
wire [ADDR_WIDTH-2:0] internal_addr = addr[ADDR_WIDTH-1:2]; // -> ignore bit 0
reg [DATA_WIDTH-1:0] rom [0:(2**(ADDR_WIDTH-2))-1];
initial begin
$readmemb("rom.mem", rom);
end
always @(posedge clk) data_out <= rom[internal_addr];
endmodule
module ram32 #(parameter ADDR_WIDTH = 16, DATA_WIDTH = 32)
(
input wire clk,
input wire [ADDR_WIDTH-1:0] addr,
output reg [DATA_WIDTH-1:0] data_out,
input wire read_enable,
input wire [DATA_WIDTH-1:0] data_in,
input wire write_enable
);
reg [DATA_WIDTH-1:0] ram [0:(2**(ADDR_WIDTH-2))-1]; // 32bit words with byte addressing
wire [ADDR_WIDTH-2:0] internal_addr = addr[ADDR_WIDTH-1:2]; // -> ignore bit 1-0
always @(posedge clk)
begin
if(read_enable)
data_out <= ram[internal_addr];
if(write_enable)
ram[internal_addr] <= data_in;
end
endmodule
module mem #(parameter ADDR_WIDTH = 32,
parameter DATA_WIDTH = 32)
(
input wire clk, rst_n,
input wire [ADDR_WIDTH-1:0] addr,
output wire [DATA_WIDTH-1:0] data_out,
input wire read_enable,
input wire [DATA_WIDTH-1:0] data_in,
input wire write_enable,
output wire io_enable,
input wire [DATA_WIDTH-1:0] io_rd_data,
output wire mem_wait
);
wire [DATA_WIDTH-1:0] ram_out, rom_out, dram_out;
// address map:
// ROM $0000 - $07FF 2K
// IO $0800 - $0FFF 2K
// RAM1 $1000 - $FFFF 60K
wire ram_cs = addr[ADDR_WIDTH-1:12] != { {(ADDR_WIDTH-12){1'b0}}};
wire ram1_cs = ram_cs && (addr[ADDR_WIDTH-1:16] == { {(ADDR_WIDTH-16){1'b0}}});
wire ram2_cs = ram_cs && !ram1_cs;
wire rom_cs = !ram_cs && addr[11] == 1'b0;
wire io_cs = !ram_cs && addr[11] == 1'b1;
assign io_enable = io_cs;
wire ram_read = ram1_cs && read_enable;
wire ram_write = ram1_cs && write_enable;
wire rom_read = rom_cs && read_enable;
reg [DATA_WIDTH-1:0] data_buf;
localparam SEL_RAM1 = 0;
localparam SEL_RAM2 = 1;
localparam SEL_ROM = 2;
localparam SEL_IO = 3;
localparam SEL_ERR = 4;
reg [1:0] out_sel;
// test
reg [1:0] wait_state;
wire dram_wait = 0;
ram32 #(.ADDR_WIDTH(16)) ram0 // 64KB RAM
(
.clk(clk),
.addr(addr[15:0]),
.data_out(ram_out),
.read_enable(ram_read),
.data_in(data_in),
.write_enable(ram_write)
);
rom32 #(.ADDR_WIDTH(11)) rom0 // 2KB ROM
(
.clk(clk),
.addr(addr[10:0]),
.data_out(rom_out),
.read_enable(rom_read)
);
assign data_out = (out_sel == SEL_RAM1 ) ? ram_out :
(out_sel == SEL_RAM2 ) ? dram_out :
(out_sel == SEL_ROM ) ? rom_out :
(out_sel == SEL_IO ) ? io_rd_data :
data_buf;
assign mem_wait = ram2_cs && dram_wait;
always @(posedge clk)
begin
data_buf <= data_out;
if(read_enable) out_sel <=
ram1_cs ? SEL_RAM1 :
ram2_cs ? SEL_RAM2:
rom_cs ? SEL_ROM :
io_cs ? SEL_IO :
SEL_ERR;
end
endmodule

View file

@ -0,0 +1,242 @@
`timescale 1ns / 1ps
`define clock cpuclk
`define clkfreq 25000000
//`define clock clk
//`define clkfreq 100000000
//`define clock clk_1hz
`define ENABLE_VGAFB
`define ENABLE_MICROSD
module top(
input wire clk,
input wire rst,
output wire led0,
input wire uart_txd_in,
output wire uart_rxd_out
`ifdef ENABLE_VGAFB
,
output wire [3:0] VGA_R,
output wire [3:0] VGA_G,
output wire [3:0] VGA_B,
output wire VGA_HS_O,
output wire VGA_VS_O
`endif
`ifdef ENABLE_MICROSD
,
output wire sd_cs_n,
output wire sd_mosi,
input wire sd_miso,
output wire sd_sck,
input wire sd_cd
`endif
);
reg [31:0] counter;
localparam ADDR_WIDTH = 32, WIDTH = 32,
ROMADDR_WIDTH = 11, IOADDR_WIDTH = 11, IOADDR_SEL = 4;
wire [ADDR_WIDTH-1:0] mem_addr;
wire [WIDTH-1:0] mem_read_data;
wire [WIDTH-1:0] mem_write_data;
(* KEEP *) wire mem_wait;
(* KEEP *) wire mem_read_enable;
(* KEEP *) wire mem_write_enable;
(* KEEP *) wire io_enable;
wire [WIDTH-1:0] io_rd_data;
wire [IOADDR_SEL-1:0] io_slot = mem_addr[IOADDR_WIDTH-1:IOADDR_WIDTH-IOADDR_SEL];
wire irq;
// assign led0 = mem_wait;
wire [WIDTH-1:0] debug_data1, debug_data2,
debug_data3, debug_data4,
debug_data5, debug_data6;
assign led0 = debug_data6[0];
wire cpuclk, cpuclk_locked;
wire dram_refclk200;
wire pixclk = cpuclk;
cpu_clkgen cpuclk_0(~rst, clk, cpuclk, cpuclk_locked);
mem #(.ADDR_WIDTH(ADDR_WIDTH), .DATA_WIDTH(WIDTH)) mem0(
.clk(`clock), .rst_n(rst), .addr(mem_addr),
.data_out(mem_read_data), .read_enable(mem_read_enable),
.data_in(mem_write_data), .write_enable(mem_write_enable),
.io_enable(io_enable),
.io_rd_data(io_rd_data),
.mem_wait(mem_wait)
);
`ifdef ENABLE_VGAFB
localparam FB_ADDR_WIDTH = 14;
wire [FB_ADDR_WIDTH-1:0] fb_rd_addr;
wire [FB_ADDR_WIDTH-1:0] fb_wr_addr;
wire [WIDTH-1:0] fb_rd_data;
wire [WIDTH-1:0] fb_wr_data;
wire fb_rd_en, fb_wr_en;
wire fb_cs_en = io_enable && (io_slot == 2);
assign fb_rd_en = fb_cs_en && mem_read_enable;
assign fb_wr_en = fb_cs_en && mem_write_enable;
assign fb_wr_data = mem_write_data;
vgafb vgafb0(`clock, pixclk, rst,
mem_addr[3:0], fb_rd_data, fb_wr_data,
fb_rd_en, fb_wr_en,
VGA_HS_O, VGA_VS_O, VGA_R, VGA_G, VGA_B);
`endif
// SPI SD card controller -------------------------------------------------------------------
`ifdef ENABLE_MICROSD
wire [7:0] spi_tx_data;
(*KEEP*) wire [7:0] spi_rx_data;
wire spi_tx_ready; // ready to transmit new data
wire spi_tx_empty; // tx fifo is empty
wire spi_rx_avail; // a byte has been received
wire spi_rx_ovr; // receiver overrun
wire spi_tx_write; // write strobe
wire spi_rx_read; // read strobe (clears rx_avail)
wire spi_card_detect; // true is card is present
wire spi_card_changed; // card_detect signal has changed
wire spi_card_busy; // card is busy (MISO/DO is 0)
wire spi_ctrl_write; // set the following flags
wire spi_rx_filter_en; // set to wait for start bit (1-to-0) when receiving
wire spi_txrx_en; // enable transmitter and receiver
wire spi_sclk_f_en; // enable spi clock without transceiver
wire spi_sclk_div_wr; // set clock divider from tx_data
wire spi_cs; // cs signal for spi controller
wire [WIDTH-1:0] spi_rd_data;
assign spi_cs = io_enable && (io_slot == 1);
// spi read data: [ 0,...,0,cd,cc,cb,tr,te,ra,ro,d,d,d,d,d,d,d,d ]
// cd = card detect, cc = card changed, cb = card busy,
// tr = transmitter ready, te = tx fifo empty,
// ra = received byte available, ro = receive overrun, d = received byte
assign spi_rd_data =
{ {WIDTH-15{1'b0}}, spi_card_detect, spi_card_changed, spi_card_busy,
spi_tx_ready, spi_tx_empty,
spi_rx_avail, spi_rx_ovr, spi_rx_data };
// spi write data: [ 0,...,0,CW,CF,Cx,Cc,Cd,DR,DW,d,d,d,d,d,d,d,d ]
// CW = control write, CF = enable receive filter, Cx = enable transceiver,
// Cc = force spi clock on, Cd = write clock divider,
// DR = read acknowledge, DW = data write, d = byte to be sent
assign spi_ctrl_write = spi_cs && mem_write_enable && mem_write_data[14];
assign spi_rx_filter_en = mem_write_data[13];
assign spi_txrx_en = mem_write_data[12];
assign spi_sclk_f_en = mem_write_data[11];
assign spi_sclk_div_wr = spi_cs && mem_write_enable && mem_write_data[10];
assign spi_rx_read = mem_write_data[9];
assign spi_tx_write = spi_cs && mem_write_enable && mem_write_data[8];
assign spi_tx_data = mem_write_data[7:0];
sdspi sdspi0(.clk(`clock), .reset(~rst),
.tx_data(spi_tx_data), .rx_data(spi_rx_data),
.tx_ready(spi_tx_ready), .tx_empty(spi_tx_empty),
.rx_avail(spi_rx_avail), .rx_ovr(spi_rx_ovr),
.tx_write(spi_tx_write), .rx_read(spi_rx_read),
.card_detect(spi_card_detect), .card_changed(spi_card_changed), .card_busy(spi_card_busy),
// ctrl_write is used with rx_filter_en, txrx_en and spiclk_f_en
.ctrl_write(spi_ctrl_write),
.rx_filter_en(spi_rx_filter_en), .txrx_en(spi_txrx_en), .spiclk_f_en(spi_sclk_f_en),
//
.spiclk_div_wr(spi_sclk_div_wr),
.sd_cs_n(sd_cs_n),
.sd_mosi(sd_mosi), .sd_miso(sd_miso), .sd_sck(sd_sck), .sd_cd(sd_cd));
`endif
// UART -----------------------------------------------------------------------
// uart write data: [ 0, 0, 0, 0, 0, T, C, 0, c, c, c, c, c, c, c, c ]
// T = transmit enable, C = receiver clear, c = 8-bit-character
// uart read data: [ 0, 0, 0, 0, 0, 0, A, B, c, c, c, c, c, c, c, c ]
// A = char available, B = tx busy, c = 8-bit-character
wire uart_cs = io_enable && (io_slot == 0);
wire uart_tx_en = uart_cs && mem_write_enable && mem_write_data[10];
wire uart_rx_clear = uart_cs && mem_write_enable && mem_write_data[9];
wire uart_rx_avail;
wire uart_rx_busy, uart_tx_busy;
wire uart_err;
wire [7:0] uart_rx_data;
wire [7:0] uart_tx_data;
wire [31:0] uart_baud = 32'd115200;
wire [WIDTH-1:0] uart_rd_data;
assign uart_tx_data = mem_write_data[7:0];
assign uart_rd_data = { {WIDTH-10{1'b1}}, uart_rx_avail, uart_tx_busy, uart_rx_data };
reg timer_tick;
reg[23:0] tick_count;
wire [1:0] irq_in = { timer_tick, uart_rx_avail };
wire [1:0] irqc_rd_data0;
wire [WIDTH-1:0] irqc_rd_data = { tick_count, 6'b0, irqc_rd_data0 };
wire irqc_seten = mem_write_data[7];
wire irqc_cs = io_enable && (io_slot == 3);
assign io_rd_data = (io_slot == 0) ? uart_rd_data :
`ifdef ENABLE_MICROSD
(io_slot == 1) ? spi_rd_data :
`endif
`ifdef ENABLE_VGAFB
(io_slot == 2) ? fb_rd_data :
`endif
(io_slot == 3) ? irqc_rd_data:
-1;
buart #(.CLKFREQ(`clkfreq)) uart0(`clock, rst,
uart_baud,
uart_txd_in, uart_rxd_out,
uart_rx_clear, uart_tx_en,
uart_rx_avail, uart_tx_busy,
uart_tx_data, uart_rx_data);
// CPU -----------------------------------------------------------------
stackcpu cpu0(.clk(`clock), .rst(rst), .irq(irq),
.addr(mem_addr),
.data_in(mem_read_data), .read_enable(mem_read_enable),
.data_out(mem_write_data), .write_enable(mem_write_enable),
.mem_wait(mem_wait),
.led1(led1), .led2(led2), .led3(led3),
.debug_out1(debug_data1),
.debug_out2(debug_data2),
.debug_out3(debug_data3),
.debug_out4(debug_data4),
.debug_out5(debug_data5),
.debug_out6(debug_data6));
// Interrupt Controller
irqctrl irqctrl0(`clock, irq_in, irqc_cs, mem_write_enable,
irqc_seten, irqc_rd_data0,
irq);
// count clock ticks
// generate interrupt every 20nth of a second
always @ (posedge `clock)
begin
counter <= counter + 1;
if (counter >= (`clkfreq/20))
begin
counter <= 0;
timer_tick <= 1;
tick_count <= tick_count + 1'b1;
end
else
begin
timer_tick <= 0;
end
end
endmodule