qf100: add sky130 sram, rejigger bram in tests

main
q3k 2022-03-20 15:53:58 +01:00
parent ef37383d10
commit 4e7b4ee21e
10 changed files with 551 additions and 166 deletions

View File

@ -11,34 +11,46 @@ bluespec_library(
"//wishbone/peripherals:spi",
"//wishbone/peripherals:gpio",
"//systems/qf100",
"//systems/qf100:sky130_sram",
"//systems/qf100:spi_flash_emulator",
],
synthesize = {
"Board": [
"mkQF105",
"mkQF100SPIFlashEmulator",
],
},
data = [
":bram.bin",
":flash.bin",
],
)
rtl_bundle(
name = "qf100",
srcs = [
":sky130_sram_2kbyte_1rw1r_32x512_8.v"
],
outputs = {
"mkLanaiCPU": [],
"mkQF100Memory": [],
"mkLanaiFrontend": [],
"mkQF100SPI": [],
"mkQF100GPIO": [],
"mkQF100KSC": [],
"mkQF100Fabric": [],
"mkQF100FlashController": [],
"mkQF105": [
"mkLanaiCPU",
"mkQF100Memory",
"mkLanaiFrontend",
"mkQF100SPI",
"mkQF100GPIO",
"mkQF100KSC",
"mkQF100Fabric",
"mkQF100FlashController",
"sky130_sram_2kbyte_1rw1r_32x512_8",
],
"mkQF100SPIFlashEmulator": [],
},
deps = [
":QF100"
":QF100",
],
)

View File

@ -8,6 +8,7 @@ import Connectable :: *;
import TieOff :: *;
import QF100 :: *;
import Sky130SRAM :: *;
import Lanai_IFC :: *;
import Lanai_CPU :: *;
@ -17,6 +18,14 @@ import WishboneCrossbar :: *;
import WishboneSPI :: *;
import WishboneGPIO :: *;
import SPIFlashEmulator :: *;
(* synthesize *)
module mkQF100SPIFlashEmulator(SPIFlashEmulator);
let res <- mkSPIFlashEmulator("boards/qf100/flash.bin");
return res;
endmodule
interface CaravelUserProject;
// Logic Analyzer signals
(* always_ready, always_enabled, prefix="" *)
@ -59,6 +68,10 @@ typedef struct {
module mkQF105Inner(CaravelUserProject);
let qf100 <- mkQF100;
let sram <- mkSky130SRAM;
mkConnection(qf100.ram_imem, sram.portB);
mkConnection(qf100.ram_dmem, sram.portA);
method Bit#(128) la_out = 0;
method Bit#(3) irq = 0;

View File

@ -0,0 +1,160 @@
// OpenRAM SRAM model
// Words: 512
// Word size: 32
// Write size: 8
module sky130_sram_2kbyte_1rw1r_32x512_8(
`ifdef USE_POWER_PINS
vccd1,
vssd1,
`endif
// Port 0: RW
clk0,csb0,web0,wmask0,addr0,din0,dout0,
// Port 1: R
clk1,csb1,addr1,dout1
);
parameter NUM_WMASKS = 4 ;
parameter DATA_WIDTH = 32 ;
parameter ADDR_WIDTH = 9 ;
parameter RAM_DEPTH = 1 << ADDR_WIDTH;
// FIXME: This delay is arbitrary.
parameter DELAY = 3 ;
parameter VERBOSE = 1 ; //Set to 0 to only display warnings
parameter T_HOLD = 1 ; //Delay to hold dout value after posedge. Value is arbitrary
`ifdef USE_POWER_PINS
inout vccd1;
inout vssd1;
`endif
input clk0; // clock
input csb0; // active low chip select
input web0; // active low write control
input [NUM_WMASKS-1:0] wmask0; // write mask
input [ADDR_WIDTH-1:0] addr0;
input [DATA_WIDTH-1:0] din0;
output [DATA_WIDTH-1:0] dout0;
input clk1; // clock
input csb1; // active low chip select
input [ADDR_WIDTH-1:0] addr1;
output [DATA_WIDTH-1:0] dout1;
reg csb0_reg;
reg web0_reg;
reg [NUM_WMASKS-1:0] wmask0_reg;
reg [ADDR_WIDTH-1:0] addr0_reg;
reg [DATA_WIDTH-1:0] din0_reg;
reg [DATA_WIDTH-1:0] dout0;
// All inputs are registers
always @(posedge clk0)
begin
csb0_reg = csb0;
web0_reg = web0;
wmask0_reg = wmask0;
addr0_reg = addr0;
din0_reg = din0;
#(T_HOLD) dout0 = 32'bx;
if ( !csb0_reg && web0_reg && VERBOSE )
$display($time," Reading %m addr0=%b dout0=%b",addr0_reg,mem[addr0_reg]);
if ( !csb0_reg && !web0_reg && VERBOSE )
$display($time," Writing %m addr0=%b din0=%b wmask0=%b",addr0_reg,din0_reg,wmask0_reg);
end
reg csb1_reg;
reg [ADDR_WIDTH-1:0] addr1_reg;
reg [DATA_WIDTH-1:0] dout1;
// All inputs are registers
always @(posedge clk1)
begin
csb1_reg = csb1;
addr1_reg = addr1;
if (!csb0 && !web0 && !csb1 && (addr0 == addr1))
$display($time," WARNING: Writing and reading addr0=%b and addr1=%b simultaneously!",addr0,addr1);
#(T_HOLD) dout1 = 32'bx;
if ( !csb1_reg && VERBOSE )
$display($time," Reading %m addr1=%b dout1=%b",addr1_reg,mem[addr1_reg]);
end
reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1];
// Memory Write Block Port 0
// Write Operation : When web0 = 0, csb0 = 0
always @ (negedge clk0)
begin : MEM_WRITE0
if ( !csb0_reg && !web0_reg ) begin
if (wmask0_reg[0])
mem[addr0_reg][7:0] = din0_reg[7:0];
if (wmask0_reg[1])
mem[addr0_reg][15:8] = din0_reg[15:8];
if (wmask0_reg[2])
mem[addr0_reg][23:16] = din0_reg[23:16];
if (wmask0_reg[3])
mem[addr0_reg][31:24] = din0_reg[31:24];
end
end
// Memory Read Block Port 0
// Read Operation : When web0 = 1, csb0 = 0
always @ (negedge clk0)
begin : MEM_READ0
if (!csb0_reg && web0_reg)
dout0 <= #(DELAY) mem[addr0_reg];
end
// Memory Read Block Port 1
// Read Operation : When web1 = 1, csb1 = 0
always @ (negedge clk1)
begin : MEM_READ1
if (!csb1_reg)
dout1 <= #(DELAY) mem[addr1_reg];
end
endmodule
module sky130_sram_2kbyte_1rw1r_32x512_8_wrapper(
`ifdef USE_POWER_PINS
vccd1,
vssd1,
`endif
// Port 0: RW
clk0,cs0,web0,wmask0,addr0,din0,dout0,
// Port 1: R
clk1,cs1,addr1,dout1
);
parameter NUM_WMASKS = 4 ;
parameter DATA_WIDTH = 32 ;
parameter ADDR_WIDTH = 9 ;
parameter RAM_DEPTH = 1 << ADDR_WIDTH;
// FIXME: This delay is arbitrary.
parameter DELAY = 3 ;
parameter VERBOSE = 1 ; //Set to 0 to only display warnings
parameter T_HOLD = 1 ; //Delay to hold dout value after posedge. Value is arbitrary
`ifdef USE_POWER_PINS
inout vccd1;
inout vssd1;
`endif
input clk0; // clock
input cs0; // active high chip select
input web0; // active low write control
input [NUM_WMASKS-1:0] wmask0; // write mask
input [ADDR_WIDTH-1:0] addr0;
input [DATA_WIDTH-1:0] din0;
output [DATA_WIDTH-1:0] dout0;
input clk1; // clock
input cs1; // active high chip select
input [ADDR_WIDTH-1:0] addr1;
output [DATA_WIDTH-1:0] dout1;
sky130_sram_2kbyte_1rw1r_32x512_8 inner(
`ifdef USE_POWER_PINS
.vccd1(vccd1),
.vssd1(vssd1),
`endif
.clk0(clk0), .csb0(!cs0), .web0(web0), .wmask0(wmask0), .addr0(addr0), .din0(din0), .dout0(dout0),
.clk1(clk1), .csb1(!cs1), .addr1(addr1), .dout1(dout1)
);
endmodule

View File

@ -6,7 +6,7 @@ bluespec_library(
"LanaiFrontend.bsv",
],
synthesize = {
#"SPIFlashController": ["mkTbFlashController"],
"LanaiFrontend": ["mkLanaiFrontend"],
},
deps = [
"//lanai",

View File

@ -76,6 +76,7 @@ module mkFork(Fork#(t)) provisos (Routable#(t), Bits#(t, _));
endinterface
endmodule
(* synthesize *)
module mkLanaiFrontend(LanaiFrontend);
Fork#(Word) forkIMem <- mkFork;
Fork#(DMemReq) forkDMem <- mkFork;

View File

@ -1,6 +1,22 @@
load("//build/bluespec:rules.bzl", "bluespec_library", "bluesim_test")
load("//build/synthesis:rules.bzl", "rtl_bundle")
bluespec_library(
name = "sky130_sram",
srcs = [
"Sky130SRAM.bsv",
],
synthesize = {
"Sky130SRAM": [
"mkSky130SRAM",
],
},
deps = [
"//lanai",
],
visibility = [ "//visibility:public" ],
)
bluespec_library(
name = "qf100",
srcs = [
@ -12,14 +28,17 @@ bluespec_library(
"//lanai/frontend:spi_flash_controller",
"//wishbone/peripherals:spi",
"//wishbone/peripherals:gpio",
"//wishbone/peripherals:kitchen_sink",
],
synthesize = {
"QF100": [
"mkQF100",
"mkQF100Memory",
"mkQF100BlockRAM",
"mkQF100SPI",
"mkQF100GPIO",
"mkQF100KSC",
"mkQF100Fabric",
"mkQF100FlashController",
],
},
visibility = [ "//visibility:public" ],
@ -36,6 +55,7 @@ bluespec_library(
],
deps = [
":qf100",
":sky130_sram",
],
synthesize = {
"Tb": [
@ -58,4 +78,5 @@ bluespec_library(
srcs = [
"SPIFlashEmulator.bsv",
],
visibility = [ "//visibility:public" ],
)

View File

@ -15,21 +15,24 @@ import RAM :: *;
import WishboneCrossbar :: *;
import WishboneSPI :: *;
import WishboneGPIO :: *;
import WishboneKitchenSink :: *;
Bit#(1) wbAddrSPI = 0;
Bit#(1) wbAddrGPIO = 1;
Bit#(2) wbAddrSPI = 0;
Bit#(2) wbAddrGPIO = 1;
Bit#(2) wbAddrKSC = 2;
function Maybe#(WishboneCrossbar::DecodedAddr#(2, 32)) decoder(Bit#(32) address);
function Maybe#(WishboneCrossbar::DecodedAddr#(3, 32)) decoder(Bit#(32) address);
return case (address) matches
32'h4001_30??: tagged Valid DecodedAddr { downstream: wbAddrSPI, address: address & 32'hff };
32'h4001_08??: tagged Valid DecodedAddr { downstream: wbAddrGPIO, address: address & 32'hff };
32'h4001_1c??: tagged Valid DecodedAddr { downstream: wbAddrKSC, address: address & 32'hff };
default: tagged Invalid;
endcase;
endfunction
(* synthesize *)
module mkQF100Memory(Lanai_BlockRAM#(2048));
module mkQF100BlockRAM(Lanai_BlockRAM#(2048));
Lanai_BlockRAM#(2048) inner <- mkBlockMemory(tagged Invalid);
return inner;
endmodule
@ -50,22 +53,40 @@ module mkQF100GPIO(WishboneGPIO::GPIOController#(32));
method oe = res.oe;
endmodule
(* synthesize *)
module mkQF100KSC(WishboneKitchenSink::KitchenSinkController#(32));
let res <- mkKitchenSinkController;
interface slave = res.slave;
endmodule
interface QF100Fabric;
interface Wishbone::Slave#(32, 32, 4) cpu;
interface Wishbone::Master#(32, 32, 4) spi;
interface Wishbone::Master#(32, 32, 4) gpio;
interface Wishbone::Master#(32, 32, 4) ksc;
endinterface
(* synthesize *)
module mkQF100Fabric(QF100Fabric);
WishboneCrossbar::Crossbar#(1, 2, 32, 32, 4) fabric <- mkCrossbar(decoder);
WishboneCrossbar::Crossbar#(1, 3, 32, 32, 4) fabric <- mkCrossbar(decoder);
interface cpu = fabric.upstreams[0];
interface spi = fabric.downstreams[wbAddrSPI];
interface gpio = fabric.downstreams[wbAddrGPIO];
interface ksc = fabric.downstreams[wbAddrKSC];
endmodule
(* synthesize *)
module mkQF100FlashController(SPIFlashController#(16, 16));
SPIFlashController#(16, 16) fmc <- mkSPIFlashController;
return fmc;
endmodule
interface QF100;
// RAM.
interface Client#(Word, Word) ram_imem;
interface Client#(DMemReq, Word) ram_dmem;
// Memory SPI.
interface WishboneSPI::Master mspi;
(* always_ready *)
@ -91,11 +112,7 @@ module mkQF100(QF100);
mkConnection(cpu.imem_client, frontend.core_imem);
mkConnection(cpu.dmem_client, frontend.core_dmem);
Lanai_BlockRAM#(2048) ram <- mkQF100Memory;
mkConnection(frontend.ram_imem, ram.memory.imem);
mkConnection(frontend.ram_dmem, ram.memory.dmem);
SPIFlashController#(16, 64) fmc <- mkSPIFlashController;
SPIFlashController#(16, 16) fmc <- mkQF100FlashController;
mkConnection(frontend.fmc_imem, fmc.serverA);
rule fmcDMemTranslate;
let req <- frontend.fmc_dmem.request.get();
@ -112,6 +129,9 @@ module mkQF100(QF100);
WishboneGPIO::GPIOController#(32) gpioCtrl <- mkQF100GPIO;
mkConnection(fabric.gpio, gpioCtrl.slave);
WishboneKitchenSink::KitchenSinkController#(32) ksCtrl <- mkQF100KSC;
mkConnection(fabric.ksc, ksCtrl.slave);
interface mspi = fmc.spi;
method Bool mspi_csb;
return unpack(fmc.csb);
@ -120,6 +140,8 @@ module mkQF100(QF100);
method gpio_oe = gpioCtrl.oe;
method gpio_out = gpioCtrl.out;
method gpio_in = gpioCtrl.in;
interface ram_imem = frontend.ram_imem;
interface ram_dmem = frontend.ram_dmem;
endmodule
endpackage

View File

@ -0,0 +1,144 @@
package Sky130SRAM;
import FIFO :: *;
import SpecialFIFOs :: *;
import GetPut :: *;
import ClientServer :: *;
import Lanai_Memory :: *;
import Lanai_IFC :: *;
interface Sky130SRAMCore;
method Action request0(Bit#(9) addr0, Bit#(32) din0, Bool web0, Bit#(4) wmask0);
method Bit#(32) response0;
method Action request1(Bit#(9) addr1);
method Bit#(32) response1;
endinterface
import "BVI" sky130_sram_2kbyte_1rw1r_32x512_8_wrapper =
module mkSky130SRAMCore#(Clock clk0, Reset rst0, Clock rclk1, Reset rst1)(Sky130SRAMCore);
default_clock no_clock;
default_reset no_reset;
input_clock clk0(clk0, (*unused*)clk0_gate) = clk0;
input_reset rsb0() = rst0;
input_reset rsb1() = rst1;
method request0(addr0, din0, web0, wmask0) clocked_by (clk0) enable (cs0);
method dout0 response0 clocked_by (clk0);
schedule (response0) SB (request0);
input_clock clk1(clk1, (*unused*)clk1_gate) = clk0;
method request1(addr1) clocked_by (clk1) enable (cs1);
method dout1 response1 clocked_by (clk1);
schedule (response1) SB (request1);
endmodule
interface Sky130SRAM;
interface Server#(DMemReq, Word) portA;
interface Server#(Word, Word) portB;
endinterface
(* synthesize *)
module mkSky130SRAM(Sky130SRAM);
Clock clk <- exposeCurrentClock;
Reset rst <- exposeCurrentReset;
let core <- mkSky130SRAMCore(clk, rst, clk, rst);
FIFO#(void) inFlight0 <- mkPipelineFIFO;
FIFO#(void) inFlight1 <- mkPipelineFIFO;
interface Server portA;
interface Put request;
method Action put(DMemReq req);
inFlight0.enq(?);
Bit#(4) wmask = 0;
Bit#(32) din = 0;
Bool web = False;
if (req.data matches tagged Valid .val) begin
web = True;
case (req.width) matches
tagged Word: begin
//$display("%x: DMEM WRITE REQ, word [%x] <- %x", req.pc, req.addr, val);
wmask = 4'b1111;
din = val;
end
tagged HalfWord: begin
Bit#(32) valH = zeroExtend(val[15:0]);
//$display("%x: DMEM WRITE REQ, hword [%x] <- %x", req.pc, req.addr, valH);
case (req.addr[1]) matches
1'b1: begin
wmask = 4'b0011;
din = valH;
end
1'b0: begin
wmask = 4'b1100;
din = valH << 16;
end
endcase
if (req.addr[1] == 1) begin
wmask = 4'b1100;
din = val << 16;
end else begin
wmask = 4'b0011;
din = zeroExtend(val[15:0]);
end
end
tagged Byte: begin
Bit#(32) valB = zeroExtend(val[7:0]);
//$display("%x: DMEM WRITE REQ, byte [%x] <- %x", req.pc, req.addr, valB);
case (req.addr[1:0]) matches
2'b11: begin
wmask = 4'b0001;
din = valB;
end
2'b10: begin
wmask = 4'b0010;
din = valB << 8;
end
2'b01: begin
wmask = 4'b0100;
din = valB << 16;
end
2'b00: begin
wmask = 4'b1000;
din = valB << 24;
end
endcase
end
endcase
end
core.request0(req.addr[8:0], din, !web, wmask);
endmethod
endinterface
interface Get response;
method ActionValue#(Bit#(32)) get();
inFlight0.deq;
let res = core.response0;
return res;
endmethod
endinterface
endinterface
interface Server portB;
interface Put request;
method Action put(Bit#(32) address);
inFlight1.enq(?);
core.request1(address[8:0]);
endmethod
endinterface
interface Get response;
method ActionValue#(Bit#(32)) get();
inFlight1.deq;
let res = core.response1;
return res;
endmethod
endinterface
endinterface
endmodule
endpackage

View File

@ -1,15 +1,22 @@
package Tb;
import QF100 :: *;
import SPIFlashEmulator :: *;
import StmtFSM :: *;
import Assert :: *;
import Connectable :: *;
import WishboneSPI :: *;
import QF100 :: *;
import Lanai_Memory :: *;
import SPIFlashEmulator :: *;
(* synthesize *)
module mkTbQF100(Empty);
QF100 qf100 <- mkQF100;
Lanai_BlockRAM#(2048) bram <- mkQF100BlockRAM;
SPIFlashEmulator emu <- mkSPIFlashEmulator("systems/qf100/flash.bin");
mkConnection(qf100.ram_imem, bram.memory.imem);
mkConnection(qf100.ram_dmem, bram.memory.dmem);
rule feed_qf100_in;
qf100.gpio_in(0);
qf100.spi.miso(False);
@ -22,13 +29,18 @@ module mkTbQF100(Empty);
emu.csb(qf100.mspi_csb);
endrule
Reg#(Bit#(32)) tmp <- mkReg(0);
Stmt test = seq
for (tmp <= 0; tmp <= 20000; tmp <= tmp + 1) seq
noAction;
endseq
endseq;
mkAutoFSM(test);
Reg#(Bit#(32)) counter <- mkReg(0);
rule upcount;
counter <= counter + 1;
endrule
rule timeout;
dynamicAssert(counter < 40_000, "Timeout.");
endrule
rule findGPIOPatern;
if (qf100.gpio_out == 3) begin
$finish(0);
end
endrule
endmodule
endpackage

View File

@ -1,9 +1,6 @@
9293fffc
02900008
22100020
01814001
518c0800
9196fff4
22100018
90120004
01812000
518c0000
@ -14,7 +11,7 @@ c1a41a00
91920008
07880010
9793fffc
e0000134
e00002d4
00000001
01812000
518c0010
@ -23,54 +20,161 @@ e0000134
c4a41a00
94920008
04810000
54a40170
54a40344
94920004
91900000
07880010
9793fffc
e0000290
00000001
01812000
518c0000
f4820001
948c0000
01812000
518c0010
06012000
56300004
91b00000
01812000
518c0008
948c0000
01812000
518c0810
04812000
54a4000c
07880010
9793fffc
e00000f8
91a40000
07880010
9793fffc
e0000138
00000001
9293fffc
02900008
22100008
81940000
0481dead
54a4c0de
91a40000
e00000f0
00000001
9293fffc
02900008
22100008
51800000
04812000
54a40000
f6020001
96240000
04812000
54a40010
06812000
56b40004
94b40000
8696fff4
04812000
54a40008
96240000
04812000
54a40810
06012000
5630000c
94b00000
04811111
54a41111
94b40000
56340004
94b00000
448d0000
94b6000c
e00000e0
04814001
54a4080c
06011111
56301111
9626fff4
9626fff8
862613f8
468d0000
96a40000
018c0001
e0000124
96240000
9293fffc
02900008
22100018
01810000
518c0324
91920008
f1820006
91920004
01810000
518c031b
91900000
07880010
9793fffc
e000019c
00000001
07880010
9793fffc
e0000138
00000001
9293fffc
02900008
22100008
8116fffc
02140000
8296fff8
9293fffc
02900008
22100030
81960008
84940000
86160004
9496fff0
9616fff4
24940010
9496ffd8
f4820001
9496ffdc
9016ffe0
04810000
54a40334
9496ffe8
9016ffec
91920004
21940028
91900000
07880010
9793fffc
e000020c
00000001
07880010
9793fffc
e0000138
00000001
9293fffc
02900008
22100020
81960004
84940000
06010000
56300334
9616ffe8
06010000
56300334
9616ffec
9496fff0
9196fff4
21940018
91900000
07880010
9793fffc
e00000d4
00000001
07880010
9793fffc
e0000138
00000001
9293fffc
02900008
22100008
0181c859
540cc8f5
01813edc
548caf6c
8116fffc
02140000
8296fff8
9293fffc
02900008
22100008
81960008
200e0000
e6000129
e60002c9
84140000
84960004
56200000
f6a75401
f6b36000
218e0001
e6000114
e60002b4
06300001
8116fffc
02140000
@ -80,12 +184,12 @@ e6000114
22100008
81960008
200e0000
e6000165
e6000305
84140000
84960004
56200000
218e0001
e6000158
e60002f8
f4b36401
8116fffc
02140000
@ -8086,107 +8190,3 @@ f4b36401
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000