2019-04-26 21:21:50 +02:00
|
|
|
# See LICENSE for licensing information.
|
|
|
|
|
#
|
2019-06-14 17:43:41 +02:00
|
|
|
# Copyright (c) 2016-2019 Regents of the University of California and The Board
|
|
|
|
|
# of Regents for the Oklahoma Agricultural and Mechanical College
|
|
|
|
|
# (acting for and on behalf of Oklahoma State University)
|
|
|
|
|
# All rights reserved.
|
2019-04-26 21:21:50 +02:00
|
|
|
#
|
2016-11-08 18:57:35 +01:00
|
|
|
import debug
|
|
|
|
|
|
|
|
|
|
class verilog:
|
2019-01-11 23:15:16 +01:00
|
|
|
"""
|
|
|
|
|
Create a behavioral Verilog file for simulation.
|
|
|
|
|
This is inherited by the sram_base class.
|
|
|
|
|
"""
|
|
|
|
|
def __init__(self):
|
|
|
|
|
pass
|
|
|
|
|
|
2017-12-19 18:01:24 +01:00
|
|
|
def verilog_write(self,verilog_name):
|
|
|
|
|
""" Write a behavioral Verilog model. """
|
2016-11-08 18:57:35 +01:00
|
|
|
self.vf = open(verilog_name, "w")
|
2019-07-04 19:34:14 +02:00
|
|
|
# Determine if optional write mask is used
|
|
|
|
|
self.wmask_enabled = False
|
|
|
|
|
if self.word_size != self.write_size:
|
|
|
|
|
self.wmask_enabled = True
|
2016-11-08 18:57:35 +01:00
|
|
|
|
|
|
|
|
self.vf.write("// OpenRAM SRAM model\n")
|
|
|
|
|
self.vf.write("// Words: {0}\n".format(self.num_words))
|
2019-07-04 19:34:14 +02:00
|
|
|
self.vf.write("// Word size: {0}\n".format(self.word_size))
|
|
|
|
|
if self.wmask_enabled:
|
|
|
|
|
self.vf.write("// Write size: {0}\n\n".format(self.write_size))
|
2019-07-06 00:55:03 +02:00
|
|
|
else:
|
|
|
|
|
self.vf.write("\n")
|
2019-01-11 23:15:16 +01:00
|
|
|
|
|
|
|
|
self.vf.write("module {0}(\n".format(self.name))
|
|
|
|
|
for port in self.all_ports:
|
|
|
|
|
if port in self.readwrite_ports:
|
|
|
|
|
self.vf.write("// Port {0}: RW\n".format(port))
|
|
|
|
|
elif port in self.read_ports:
|
|
|
|
|
self.vf.write("// Port {0}: R\n".format(port))
|
|
|
|
|
elif port in self.write_ports:
|
|
|
|
|
self.vf.write("// Port {0}: W\n".format(port))
|
|
|
|
|
if port in self.readwrite_ports:
|
2019-07-04 19:34:14 +02:00
|
|
|
self.vf.write(" clk{0},csb{0},web{0},".format(port))
|
|
|
|
|
if self.wmask_enabled:
|
|
|
|
|
self.vf.write("wmask{},".format(port))
|
|
|
|
|
self.vf.write("ADDR{0},DIN{0},DOUT{0}".format(port))
|
2019-01-11 23:15:16 +01:00
|
|
|
elif port in self.write_ports:
|
2019-07-04 19:34:14 +02:00
|
|
|
self.vf.write(" clk{0},csb{0},".format(port))
|
|
|
|
|
if self.wmask_enabled:
|
|
|
|
|
self.vf.write("wmask{},".format(port))
|
|
|
|
|
self.vf.write("ADDR{0},DIN{0}".format(port))
|
2019-01-11 23:15:16 +01:00
|
|
|
elif port in self.read_ports:
|
|
|
|
|
self.vf.write(" clk{0},csb{0},ADDR{0},DOUT{0}".format(port))
|
|
|
|
|
# Continue for every port on a new line
|
|
|
|
|
if port != self.all_ports[-1]:
|
|
|
|
|
self.vf.write(",\n")
|
|
|
|
|
self.vf.write("\n );\n\n")
|
2019-07-06 00:08:59 +02:00
|
|
|
|
2019-07-04 19:34:14 +02:00
|
|
|
if self.wmask_enabled:
|
|
|
|
|
self.num_wmask = int(self.word_size/self.write_size)
|
|
|
|
|
self.vf.write(" parameter NUM_WMASK = {0} ;\n".format(self.num_wmask))
|
2019-07-06 00:08:59 +02:00
|
|
|
self.vf.write(" parameter DATA_WIDTH = {0} ;\n".format(self.word_size))
|
|
|
|
|
self.vf.write(" parameter ADDR_WIDTH = {0} ;\n".format(self.addr_size))
|
2016-11-08 18:57:35 +01:00
|
|
|
self.vf.write(" parameter RAM_DEPTH = 1 << ADDR_WIDTH;\n")
|
2019-01-11 23:15:16 +01:00
|
|
|
self.vf.write(" // FIXME: This delay is arbitrary.\n")
|
2016-11-08 18:57:35 +01:00
|
|
|
self.vf.write(" parameter DELAY = 3 ;\n")
|
|
|
|
|
self.vf.write("\n")
|
2019-01-11 23:15:16 +01:00
|
|
|
|
|
|
|
|
for port in self.all_ports:
|
|
|
|
|
self.add_inputs_outputs(port)
|
|
|
|
|
|
2016-11-08 18:57:35 +01:00
|
|
|
self.vf.write("\n")
|
2019-01-11 23:15:16 +01:00
|
|
|
|
|
|
|
|
for port in self.all_ports:
|
|
|
|
|
self.register_inputs(port)
|
|
|
|
|
|
|
|
|
|
# This is the memory array itself
|
|
|
|
|
self.vf.write("reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1];\n")
|
|
|
|
|
|
|
|
|
|
for port in self.all_ports:
|
|
|
|
|
if port in self.write_ports:
|
|
|
|
|
self.add_write_block(port)
|
|
|
|
|
if port in self.read_ports:
|
|
|
|
|
self.add_read_block(port)
|
|
|
|
|
|
2016-11-08 18:57:35 +01:00
|
|
|
self.vf.write("\n")
|
|
|
|
|
self.vf.write("endmodule\n")
|
2019-01-11 23:15:16 +01:00
|
|
|
self.vf.close()
|
2016-11-08 18:57:35 +01:00
|
|
|
|
|
|
|
|
|
2019-01-11 23:15:16 +01:00
|
|
|
def register_inputs(self, port):
|
|
|
|
|
"""
|
|
|
|
|
Register the control signal, address and data inputs.
|
|
|
|
|
"""
|
|
|
|
|
self.add_regs(port)
|
|
|
|
|
self.add_flops(port)
|
|
|
|
|
|
|
|
|
|
def add_regs(self, port):
|
|
|
|
|
"""
|
|
|
|
|
Create the input regs for the given port.
|
|
|
|
|
"""
|
2019-01-11 23:16:57 +01:00
|
|
|
self.vf.write(" reg csb{0}_reg;\n".format(port))
|
2019-01-11 23:15:16 +01:00
|
|
|
if port in self.readwrite_ports:
|
2019-01-11 23:16:57 +01:00
|
|
|
self.vf.write(" reg web{0}_reg;\n".format(port))
|
2019-07-06 00:08:59 +02:00
|
|
|
if port in self.write_ports:
|
|
|
|
|
if self.wmask_enabled:
|
|
|
|
|
self.vf.write(" reg [NUM_WMASK-1:0] wmask{0}_reg;\n".format(port))
|
2019-01-11 23:16:57 +01:00
|
|
|
self.vf.write(" reg [ADDR_WIDTH-1:0] ADDR{0}_reg;\n".format(port))
|
2019-01-11 23:15:16 +01:00
|
|
|
if port in self.write_ports:
|
2019-01-11 23:16:57 +01:00
|
|
|
self.vf.write(" reg [DATA_WIDTH-1:0] DIN{0}_reg;\n".format(port))
|
2019-01-11 23:15:16 +01:00
|
|
|
if port in self.read_ports:
|
2019-01-11 23:16:57 +01:00
|
|
|
self.vf.write(" reg [DATA_WIDTH-1:0] DOUT{0};\n".format(port))
|
2019-01-11 23:15:16 +01:00
|
|
|
|
|
|
|
|
def add_flops(self, port):
|
|
|
|
|
"""
|
|
|
|
|
Add the flop behavior logic for a port.
|
|
|
|
|
"""
|
|
|
|
|
self.vf.write("\n")
|
|
|
|
|
self.vf.write(" // All inputs are registers\n")
|
|
|
|
|
self.vf.write(" always @(posedge clk{0})\n".format(port))
|
|
|
|
|
self.vf.write(" begin\n")
|
|
|
|
|
self.vf.write(" csb{0}_reg = csb{0};\n".format(port))
|
|
|
|
|
if port in self.readwrite_ports:
|
|
|
|
|
self.vf.write(" web{0}_reg = web{0};\n".format(port))
|
2019-07-06 00:08:59 +02:00
|
|
|
if port in self.write_ports:
|
|
|
|
|
if self.wmask_enabled:
|
|
|
|
|
self.vf.write(" wmask{0}_reg = wmask{0};\n".format(port))
|
2019-01-11 23:15:16 +01:00
|
|
|
self.vf.write(" ADDR{0}_reg = ADDR{0};\n".format(port))
|
|
|
|
|
if port in self.write_ports:
|
|
|
|
|
self.vf.write(" DIN{0}_reg = DIN{0};\n".format(port))
|
|
|
|
|
if port in self.read_ports:
|
|
|
|
|
self.vf.write(" DOUT{0} = {1}'bx;\n".format(port,self.word_size))
|
|
|
|
|
if port in self.readwrite_ports:
|
|
|
|
|
self.vf.write(" if ( !csb{0}_reg && web{0}_reg ) \n".format(port))
|
|
|
|
|
self.vf.write(" $display($time,\" Reading %m ADDR{0}=%b DOUT{0}=%b\",ADDR{0}_reg,mem[ADDR{0}_reg]);\n".format(port))
|
|
|
|
|
elif port in self.read_ports:
|
|
|
|
|
self.vf.write(" if ( !csb{0}_reg ) \n".format(port))
|
|
|
|
|
self.vf.write(" $display($time,\" Reading %m ADDR{0}=%b DOUT{0}=%b\",ADDR{0}_reg,mem[ADDR{0}_reg]);\n".format(port))
|
|
|
|
|
if port in self.readwrite_ports:
|
|
|
|
|
self.vf.write(" if ( !csb{0}_reg && !web{0}_reg )\n".format(port))
|
2019-07-06 00:08:59 +02:00
|
|
|
if self.wmask_enabled:
|
|
|
|
|
self.vf.write(" $display($time,\" Writing %m ADDR{0}=%b DIN{0}=%b wmask{0}=%b\",ADDR{0}_reg,DIN{0}_reg,wmask{0}_reg);\n".format(port))
|
|
|
|
|
else:
|
|
|
|
|
self.vf.write(" $display($time,\" Writing %m ADDR{0}=%b DIN{0}=%b\",ADDR{0}_reg,DIN{0}_reg);\n".format(port))
|
2019-01-11 23:15:16 +01:00
|
|
|
elif port in self.write_ports:
|
|
|
|
|
self.vf.write(" if ( !csb{0}_reg )\n".format(port))
|
2019-07-06 00:08:59 +02:00
|
|
|
if self.wmask_enabled:
|
|
|
|
|
self.vf.write(" $display($time,\" Writing %m ADDR{0}=%b DIN{0}=%b wmask{0}=%b\",ADDR{0}_reg,DIN{0}_reg,wmask{0}_reg);\n".format(port))
|
|
|
|
|
else:
|
|
|
|
|
self.vf.write(" $display($time,\" Writing %m ADDR{0}=%b DIN{0}=%b\",ADDR{0}_reg,DIN{0}_reg);\n".format(port))
|
|
|
|
|
|
2019-01-11 23:15:16 +01:00
|
|
|
self.vf.write(" end\n\n")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def add_inputs_outputs(self, port):
|
|
|
|
|
"""
|
|
|
|
|
Add the module input and output declaration for a port.
|
|
|
|
|
"""
|
2019-01-11 23:16:57 +01:00
|
|
|
self.vf.write(" input clk{0}; // clock\n".format(port))
|
|
|
|
|
self.vf.write(" input csb{0}; // active low chip select\n".format(port))
|
2019-01-11 23:15:16 +01:00
|
|
|
if port in self.readwrite_ports:
|
2019-01-11 23:16:57 +01:00
|
|
|
self.vf.write(" input web{0}; // active low write control\n".format(port))
|
2019-07-04 19:34:14 +02:00
|
|
|
if (self.wmask_enabled):
|
|
|
|
|
self.vf.write(" input [NUM_WMASK-1:0] wmask{0}; // write mask\n".format(port))
|
2019-01-11 23:15:16 +01:00
|
|
|
self.vf.write(" input [ADDR_WIDTH-1:0] ADDR{0};\n".format(port))
|
|
|
|
|
if port in self.write_ports:
|
|
|
|
|
self.vf.write(" input [DATA_WIDTH-1:0] DIN{0};\n".format(port))
|
|
|
|
|
if port in self.read_ports:
|
|
|
|
|
self.vf.write(" output [DATA_WIDTH-1:0] DOUT{0};\n".format(port))
|
2016-11-08 18:57:35 +01:00
|
|
|
|
2019-01-11 23:15:16 +01:00
|
|
|
def add_write_block(self, port):
|
|
|
|
|
"""
|
|
|
|
|
Add a write port block. Multiple simultaneous writes to the same address
|
|
|
|
|
have arbitrary priority and are not allowed.
|
|
|
|
|
"""
|
|
|
|
|
self.vf.write("\n")
|
|
|
|
|
self.vf.write(" // Memory Write Block Port {0}\n".format(port))
|
|
|
|
|
self.vf.write(" // Write Operation : When web{0} = 0, csb{0} = 0\n".format(port))
|
|
|
|
|
self.vf.write(" always @ (negedge clk{0})\n".format(port))
|
|
|
|
|
self.vf.write(" begin : MEM_WRITE{0}\n".format(port))
|
|
|
|
|
if port in self.readwrite_ports:
|
2019-07-06 20:29:34 +02:00
|
|
|
if self.wmask_enabled:
|
|
|
|
|
self.vf.write(" if ( !csb{0}_reg && !web{0}_reg ) begin\n".format(port))
|
|
|
|
|
else:
|
|
|
|
|
self.vf.write(" if ( !csb{0}_reg && !web{0}_reg )\n".format(port))
|
2019-01-11 23:15:16 +01:00
|
|
|
else:
|
2019-07-06 20:29:34 +02:00
|
|
|
if self.wmask_enabled:
|
|
|
|
|
self.vf.write(" if (!csb{0}_reg) begin\n".format(port))
|
|
|
|
|
else:
|
|
|
|
|
self.vf.write(" if (!csb{0}_reg)\n".format(port))
|
2019-07-04 19:34:14 +02:00
|
|
|
|
|
|
|
|
if self.wmask_enabled:
|
|
|
|
|
for mask in range(0,self.num_wmask):
|
|
|
|
|
lower = mask * self.write_size
|
|
|
|
|
upper = lower + self.write_size-1
|
2019-07-06 00:08:59 +02:00
|
|
|
self.vf.write(" if (wmask{0}_reg[{1}])\n".format(port,mask))
|
2019-07-04 19:34:14 +02:00
|
|
|
self.vf.write(" mem[ADDR{0}_reg][{1}:{2}] = DIN{0}_reg[{1}:{2}];\n".format(port,upper,lower))
|
2019-07-06 20:29:34 +02:00
|
|
|
self.vf.write(" end\n")
|
2019-07-04 19:34:14 +02:00
|
|
|
else:
|
2019-07-06 21:27:24 +02:00
|
|
|
self.vf.write(" mem[ADDR{0}_reg] = DIN{0}_reg;\n".format(port))
|
2019-01-11 23:15:16 +01:00
|
|
|
self.vf.write(" end\n")
|
|
|
|
|
|
|
|
|
|
def add_read_block(self, port):
|
|
|
|
|
"""
|
|
|
|
|
Add a read port block.
|
|
|
|
|
"""
|
|
|
|
|
self.vf.write("\n")
|
|
|
|
|
self.vf.write(" // Memory Read Block Port {0}\n".format(port))
|
|
|
|
|
self.vf.write(" // Read Operation : When web{0} = 1, csb{0} = 0\n".format(port))
|
|
|
|
|
self.vf.write(" always @ (negedge clk{0})\n".format(port))
|
|
|
|
|
self.vf.write(" begin : MEM_READ{0}\n".format(port))
|
|
|
|
|
if port in self.readwrite_ports:
|
|
|
|
|
self.vf.write(" if (!csb{0}_reg && web{0}_reg)\n".format(port))
|
|
|
|
|
else:
|
|
|
|
|
self.vf.write(" if (!csb{0}_reg)\n".format(port))
|
|
|
|
|
self.vf.write(" DOUT{0} <= #(DELAY) mem[ADDR{0}_reg];\n".format(port))
|
|
|
|
|
self.vf.write(" end\n")
|
|
|
|
|
|