Skip to content

Commit

Permalink
first commit. no interrupts yet
Browse files Browse the repository at this point in the history
  • Loading branch information
stevej committed Oct 25, 2023
1 parent 200ac8c commit 1313158
Show file tree
Hide file tree
Showing 7 changed files with 268 additions and 34 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.DS_Store
a.out
.idea
.vscode
*.vcd
Expand Down
70 changes: 36 additions & 34 deletions info.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ project:

# If using an HDL, set wokwi_id as 0 and uncomment and list your source files here.
# Source files must be in ./src and you must list each source file separately
# source_files:
# - counter.v
# - decoder.v
# top_module: "tt_um_example" # Put the name of your top module here, must start with "tt_um_". Make it unique by including your github username
source_files:
- minipit.v
- tt_um_minipit_stevej.v
top_module: "tt_um_minipit_stevej" # Put the name of your top module here, must start with "tt_um_". Make it unique by including your github username

# How many tiles your design occupies? A single tile is about 167x108 uM.
tiles: "1x1" # Valid values: 1x1, 1x2, 2x2, 3x2, 4x2 or 8x2
Expand All @@ -20,55 +20,57 @@ yaml_version: 4
# it does and how to operate it. This info will be automatically collected and used to make a datasheet for the chip.
#
# Here is a great example: https://github.com/davidsiaw/tt02-davidsiaw-stackcalc/blob/38c5647f83aad2aec675d566aa3d67b98f0aac81/info.yaml
documentation:
author: "" # Your name
title: "" # Project title
language: "Wokwi" # other examples include Verilog, Amaranth, VHDL, etc
description: "" # Short description of what your project does
documentation:
author: "Steve Jenson" # Your name
title: "Miniature Programmable Interrupt Timer" # Project title
language: "Verilog" # other examples include Verilog, Amaranth, VHDL, etc
description: "When the given 16-bit counter reaches 0 an interrupt pin is asserted for one clock cycle." # Short description of what your project does

# Longer description of how the project works. You can use standard markdown format.
how_it_works: |
Explain how your project works
A minimal clone of a programmable interrupt timer. Inspried by the Intel 8253 but without most of the features or headaches.
# Instructions on how someone could test your project, include things like what buttons do what and how to set the clock if needed
how_to_test: |
Explain how to test your project
set input pins to 0x00. pull write enable high, address line 0 low, address line 0 low.
set input pins to 0x10, pull write enable high, address line 0 low, address line 1 high.
pull bidi pin 3 (timer_start) high, count 10 clock cycles and see if the interrupt pin has pulled high for 1 cycle
# A description of what the inputs do (e.g. red button, SPI CLK, SPI MOSI, etc).
inputs:
- none
- none
- none
- none
- none
- none
- none
- none
inputs:
- config[0] - use a clock divider
- config[1] - repeat the interrupt?
- config[2]
- config[3]
- config[4]
- config[5]
- config[6]
- config[7]
# A description of what the outputs do (e.g. status LED, SPI MISO, etc)
outputs:
- segment a
- segment b
- segment c
- segment d
- segment e
- segment f
- segment g
- dot
- divider on?
- counter set?
- pit active?
- pit in reset?
- pit currently interrupting?
- f
- g
- h
# A description of what the bidirectional I/O pins do (e.g. I2C SDA, I2C SCL, etc)
bidirectional:
- none
- none
- none
- none
- /we write enable for config
- set config address 0
- set config address 1
- start the timer
- none
- none
- none
- none

# The following fields are optional
tag: "" # comma separated list of tags: test, encryption, experiment, clock, animation, utility, industrial, pwm, fpga, alu, microprocessor, risc, riscv, sensor, signal generator, fft, filter, music, bcd, sound, serial, timer, random number generator, calculator, decoder, counter, puzzle, multiplier, game, oscillator,
tag: "pit" # comma separated list of tags: test, encryption, experiment, clock, animation, utility, industrial, pwm, fpga, alu, microprocessor, risc, riscv, sensor, signal generator, fft, filter, music, bcd, sound, serial, timer, random number generator, calculator, decoder, counter, puzzle, multiplier, game, oscillator,
external_hw: "" # Describe any external hardware needed
discord: "" # Your discord handle, used for communication and automatically assigning tapeout role after a submission
discord: "shorts_weather" # Your discord handle, used for communication and automatically assigning tapeout role after a submission
doc_link: "" # URL to longer form documentation, eg the README.md in your repository
clock_hz: 0 # Clock frequency in Hz (if required)
picture: "" # relative path to a picture in your repository (must be 512kb or less)
45 changes: 45 additions & 0 deletions src/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Makefile
# See https://docs.cocotb.org/en/stable/quickstart.html for more info

# defaults
SIM ?= icarus
TOPLEVEL_LANG ?= verilog

# normal simulation
ifneq ($(GATES),yes)

# this is the only part you should need to modify:
VERILOG_SOURCES += $(PWD)/tb.v $(PWD)/tt_um_minipit_stevej.v $(PWD)/minipit.v

else

# gate level simulation requires some extra setup, you shouldn't need to touch this
COMPILE_ARGS += -DGL_TEST
COMPILE_ARGS += -DFUNCTIONAL
COMPILE_ARGS += -DUSE_POWER_PINS
COMPILE_ARGS += -DSIM
COMPILE_ARGS += -DUNIT_DELAY=\#1
VERILOG_SOURCES += $(PDK_ROOT)/sky130A/libs.ref/sky130_fd_sc_hd/verilog/primitives.v
VERILOG_SOURCES += $(PDK_ROOT)/sky130A/libs.ref/sky130_fd_sc_hd/verilog/sky130_fd_sc_hd.v

# this gets copied in by the GDS action workflow
VERILOG_SOURCES += $(PWD)/tb.v $(PWD)/gate_level_netlist.v
endif

# TOPLEVEL is the name of the toplevel module in your Verilog or VHDL file
TOPLEVEL = tb

# MODULE is the basename of the Python test file
MODULE = test

# include cocotb's make rules to take care of the simulator setup
include $(shell cocotb-config --makefiles)/Makefile.sim

lint:
iverilog -Wall $(VERILOG_SOURCES)
verilator --timing --lint-only tb.v

# Matches what the GDS github task uses.
lint_strict:
iverilog -Wall $(VERILOG_SOURCES)
verilator --timing --lint-only -Wall tb.v
9 changes: 9 additions & 0 deletions src/minipit.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
`default_nettype none
`timescale 1ns/1ps


module minipit();



endmodule
53 changes: 53 additions & 0 deletions src/tb.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
`default_nettype none
`timescale 1ns/1ps

/*
* this testbench instantiates the module and makes some convenient wires
* that can be driven / tested by the cocotb test.py
*/

// testbench is controlled by test.py
module tb ();

// this part dumps the trace to a vcd file that can be viewed with GTKWave
initial begin
$dumpfile ("tb.vcd");
$dumpvars (0, tb);
#1;
end

// wire up the inputs and outputs
/* verilator lint_off UNDRIVEN */
wire clk;
/* verilator lint_off UNDRIVEN */
wire rst_n;
/* verilator lint_off UNDRIVEN */
wire ena;
/* verilator lint_off UNUSEDSIGNAL */
wire [7:0] ui_in;
/* verilator lint_off UNUSEDSIGNAL */
wire [7:0] uio_in;
/* verilator lint_off UNUSEDSIGNAL */
wire [7:0] uo_out;
/* verilator lint_off UNUSEDSIGNAL */
wire [7:0] uio_out;
/* verilator lint_off UNUSEDSIGNAL */
wire [7:0] uio_oe;

tt_um_minipit_stevej tt_um_minipit_stevej (
// include power ports for the Gate Level test
`ifdef GL_TEST
.VPWR( 1'b1),
.VGND( 1'b0),
`endif
.ui_in (ui_in), // Dedicated inputs
.uo_out (uo_out), // Dedicated outputs
.uio_in (uio_in), // IOs: Input path
.uio_out (uio_out), // IOs: Output path
.uio_oe (uio_oe), // IOs: Enable path (active high: 0=input, 1=output)
.ena (ena), // enable - goes high when design is selected
.clk (clk), // clock
.rst_n (rst_n) // not reset
);

endmodule
20 changes: 20 additions & 0 deletions src/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge, FallingEdge, Timer, ClockCycles


@cocotb.test()
async def test_no_config(dut):
dut._log.info("start")
clock = Clock(dut.clk, 10, units="us")
cocotb.start_soon(clock.start())

# reset
dut._log.info("reset")
dut.rst_n.value = 0
await ClockCycles(dut.clk, 1)
dut.rst_n.value = 1

await ClockCycles(dut.clk, 10)
dut._log.info("checking that interrupt is not high")
assert dut.uo_out == 0x00
104 changes: 104 additions & 0 deletions src/tt_um_minipit_stevej.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
`default_nettype none
`timescale 1ns/1ps

module tt_um_minipit_stevej (
input wire [7:0] ui_in, // Dedicated inputs - dedicated to the config bytes
output wire [7:0] uo_out, // Dedicated outputs - dedicated to status
/* verilator lint_off UNUSEDSIGNAL */
input wire [7:0] uio_in, // IOs: Bidirectional Input path
output wire [7:0] uio_out, // IOs: Bidirectional Output path
output wire [7:0] uio_oe, // IOs: Bidirectional Enable path (active high: 0=input, 1=output)
/* verilator lint_off UNUSEDSIGNAL */
input wire ena, // will go high when the design is enabled
input wire clk, // clock
input wire rst_n // reset_n - low to reset
);

wire reset = ! rst_n;
wire [7:0] status;

// registers derived from config byte 0
reg divider_on;
reg repeating;
reg counter_set;
reg interrupting;
// registers derived from uio_in;
wire we;
assign we = uio_in[0];
reg [1:0] config_address;

wire config_address_0;
assign config_address_0 = uio_in[1];

wire config_address_1;
assign config_address_1 = uio_in[2];

// wherein we need temporary storage
reg [15:0] temp_counter;

assign uio_oe = 8'b1111_0000;

// counter derived from config byte 1 concatenated with config byte 0
reg [15:0] counter;
reg [15:0] current_count;

// If the divider is enabled,
reg [8:0] divider_count;

// uo_out is always a status byte
assign uo_out = {divider_on, counter_set, 1'b0, 1'b0, interrupting, 1'b0, 1'b0, 1'b0};
assign uio_out = {1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, interrupting};

always @(posedge clk) begin
// if reset, set counter to 0
if (reset) begin
counter <= 0;
current_count <= 0;
counter_set <= 0;
divider_on <= 0;
divider_count <= 0;
end else begin
// TODO: set config_address_1, config_address_0, and we
// set config bits from ui_in;
if (we) begin
config_address <= {config_address_1, config_address_0};
case (config_address)
2'b00: begin // write config registers
divider_on <= ui_in[7];
repeating <= ui_in[6];
end
2'b01: begin // counter high byte
temp_counter <= {ui_in, 8'b0};
counter <= counter & temp_counter;
end
2'b10: begin // counter low byte
temp_counter <= {8'b0, ui_in};
counter <= counter & temp_counter;
counter_set <= 1;
end
2'b11: begin // unused
end
endcase
end // end config logic

if (counter_set && divider_on) begin
divider_count <= divider_count + 1;
if (divider_count == 10) begin
current_count <= current_count + 1;
end
end else begin
`ifdef FORMAL
assert(!divider_on);
`endif
current_count <= current_count + 1;
end

if (counter_set && (current_count == counter)) begin
// pull interrupt line high for one clock cycle
interrupting <= 1;
end else begin
interrupting <= 0;
end
end
end
endmodule

0 comments on commit 1313158

Please sign in to comment.