├── .ocamlformat
├── arty
├── outputs
│ └── .gitignore
├── .gitignore
├── dune
├── ips
│ └── design_1_clk_wiz_0_0
│ │ ├── design_1_clk_wiz_0_0_board.xdc
│ │ ├── design_1_clk_wiz_0_0_ooc.xdc
│ │ ├── design_1_clk_wiz_0_0.xdc
│ │ ├── design_1_clk_wiz_0_0.veo
│ │ ├── design_1_clk_wiz_0_0.v
│ │ ├── design_1_clk_wiz_0_0_clk_wiz.v
│ │ └── doc
│ │ └── clk_wiz_v6_0_changelog.txt
├── route.tcl
├── dune-project
├── .Xil
│ └── hardcaml_arty_top_propImpl.xdc
├── hardcaml_mips_arty.opam
├── Makefile
├── synth.tcl
├── place.tcl
├── arty.ml
└── boards
│ └── arty-a7-35
│ └── E.0
│ ├── part0_pins.xml
│ ├── mig.prj
│ └── preset.xml
├── lib
├── io
│ ├── memory.mli
│ ├── delay_test_io.mli
│ ├── io_intf.ml
│ ├── memory.ml
│ ├── uart.mli
│ ├── delay_test_io.ml
│ └── uart.ml
├── dune
├── width_check.ml
├── program.mli
├── cpu.mli
├── writeback
│ └── writeback.ml
├── instruction_decode
│ ├── stall_unit.ml
│ ├── forwarding_unit.ml
│ ├── instruction_decode.ml
│ └── control_unit.ml
├── instruction_execute
│ ├── instruction_execute.ml
│ └── alu.ml
├── instruction_fetch
│ ├── gen_next_pc.ml
│ └── instruction_fetch.ml
├── program.ml
├── cpu.ml
└── datapath.ml
├── .gitignore
├── test
├── dune
├── instruction_fetch
│ └── test_instruction_fetch.ml
├── test_writeback
│ └── test_writeback.ml
├── instruction_decode
│ ├── test_stall_unit.ml
│ ├── test_forwarding_unit.ml
│ └── test_instruction_decode.ml
├── instruction_execute
│ ├── test_alu.ml
│ └── test_instruction_execute.ml
└── io
│ ├── test_memory.ml
│ ├── uart
│ └── test_uart_tx.ml
│ └── test_delay_test_io.ml
├── dune
├── main.ml
├── dune-project
├── README.md
├── hardcaml_mips.opam
├── LICENSE
├── interactive.ml
├── .github
└── workflows
│ └── test.yml
└── CHANGELOG.md
/.ocamlformat:
--------------------------------------------------------------------------------
1 | version=0.21.0
--------------------------------------------------------------------------------
/arty/outputs/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
--------------------------------------------------------------------------------
/lib/io/memory.mli:
--------------------------------------------------------------------------------
1 | include Io_intf.Io_intf
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode
2 | _build
3 | verilog
4 | mips_datapath.v
--------------------------------------------------------------------------------
/arty/.gitignore:
--------------------------------------------------------------------------------
1 | hardcaml_arty_top.v
2 | tight_setup_hold_pins.txt
3 | .Xil
--------------------------------------------------------------------------------
/arty/dune:
--------------------------------------------------------------------------------
1 | (executable
2 | (name arty)
3 | (modules arty)
4 | (libraries hardcaml hardcaml_arty hardcaml_mips))
5 |
--------------------------------------------------------------------------------
/lib/io/delay_test_io.mli:
--------------------------------------------------------------------------------
1 | include Io_intf.Io_intf
2 |
3 | (* For testing purposes, delay writes by 2 clock cycles,
4 | * and reads by 3 clock cycles.
5 | * Used to test datapath pausing.
6 | *)
--------------------------------------------------------------------------------
/lib/dune:
--------------------------------------------------------------------------------
1 | (library
2 | (name Mips)
3 | (public_name hardcaml_mips)
4 | (libraries hardcaml hardcaml_arty)
5 | (preprocess
6 | (pps ppx_jane ppx_deriving_hardcaml)))
7 |
8 | (include_subdirs unqualified)
9 |
--------------------------------------------------------------------------------
/arty/ips/design_1_clk_wiz_0_0/design_1_clk_wiz_0_0_board.xdc:
--------------------------------------------------------------------------------
1 | #--------------------Physical Constraints-----------------
2 |
3 | set_property BOARD_PIN {clk} [get_ports clk_in1]
4 | set_property BOARD_PIN {reset} [get_ports resetn]
5 |
--------------------------------------------------------------------------------
/test/dune:
--------------------------------------------------------------------------------
1 | (library
2 | (name test_mips)
3 | (inline_tests
4 | (flags (-verbose)))
5 | (libraries hardcaml hardcaml_waveterm hardcaml_mips)
6 | (preprocess
7 | (pps ppx_jane ppx_expect)))
8 |
9 | (include_subdirs unqualified)
10 |
--------------------------------------------------------------------------------
/dune:
--------------------------------------------------------------------------------
1 | (executable
2 | (name main)
3 | (modules main)
4 | (libraries hardcaml hardcaml_mips))
5 |
6 | (executable
7 | (name interactive)
8 | (modules interactive)
9 | (libraries hardcaml hardcaml_waveterm hardcaml_waveterm.interactive hardcaml_mips))
10 |
--------------------------------------------------------------------------------
/lib/width_check.ml:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 |
3 | module With_interface (I : Interface.S) (O : Interface.S) =
4 | struct
5 | let check_widths circuit_impl i =
6 | I.Of_signal.assert_widths i;
7 | let out = circuit_impl i in
8 | O.Of_signal.assert_widths out;
9 | out
10 | end
11 |
--------------------------------------------------------------------------------
/lib/program.mli:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 |
3 | type t
4 |
5 | (* The input should be a list of MIPS instructions in hexadecimal format *)
6 | val create : string list -> t
7 |
8 | val to_signals : t -> Signal.t list
9 |
10 | (* An example program instance used for testing *)
11 | val sample : t
12 |
--------------------------------------------------------------------------------
/lib/cpu.mli:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 |
3 | module I = Hardcaml_arty.User_application.I
4 |
5 | module O : sig
6 | type 'a t = {
7 | uart_tx : 'a Hardcaml_arty.Uart.Byte_with_valid.t;
8 | ethernet : 'a Hardcaml_arty.User_application.Ethernet.O.t;
9 | writeback_data : 'a;
10 | writeback_pc : 'a;
11 | }
12 | [@@deriving sexp_of, hardcaml]
13 | end
14 |
15 | val circuit_impl : Program.t -> Scope.t -> Signal.t I.t -> Signal.t O.t
16 |
--------------------------------------------------------------------------------
/main.ml:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 | open Mips
3 | module MipsCircuit = Circuit.With_interface (Cpu.I) (Cpu.O)
4 |
5 | let scope = Scope.create ()
6 |
7 | let circuit =
8 | let bound_circuit_impl = Cpu.circuit_impl Program.sample scope in
9 | MipsCircuit.create_exn ~name:"cpu" bound_circuit_impl
10 |
11 | let output_mode = Rtl.Output_mode.To_file("mips_cpu.v")
12 |
13 | let () = Rtl.output ~output_mode ~database:(Scope.circuit_database scope) Verilog circuit
14 |
--------------------------------------------------------------------------------
/arty/route.tcl:
--------------------------------------------------------------------------------
1 | set_param board.repoPaths "boards/"
2 | set output_dir "outputs/"
3 |
4 | open_checkpoint $output_dir/post_place.dcp
5 |
6 | route_design
7 |
8 | write_checkpoint -force $output_dir/post_route
9 | report_timing_summary -file $output_dir/post_route_timing_summary.rpt
10 | report_bus_skew -file $output_dir/post_route_bus_skew.rpt
11 | report_utilization -file $output_dir/post_route_utilization.rpt
12 | write_bitstream -force $output_dir/hardcaml_arty_top.bit
13 |
--------------------------------------------------------------------------------
/dune-project:
--------------------------------------------------------------------------------
1 | (lang dune 2.8)
2 |
3 | (cram enable)
4 |
5 | (package
6 | (name hardcaml_mips)
7 | (synopsis "A simple MIPS CPU learning project in Hardcaml."))
8 |
9 | (version 1.0.0)
10 |
11 | (generate_opam_files true)
12 |
13 | (source
14 | (github askvortsov1/hardcaml-mips))
15 |
16 | (license MIT)
17 |
18 | (authors "Alexander Skvortsov" "Mayur Deshpande")
19 |
20 | (maintainers "sasha.skvortsov109@gmail.com")
21 |
22 | (homepage "https://ceramichacker.com/blog/category/hardcaml-mips")
23 |
--------------------------------------------------------------------------------
/arty/dune-project:
--------------------------------------------------------------------------------
1 | (lang dune 2.8)
2 |
3 | (cram enable)
4 |
5 | (package
6 | (name hardcaml_mips_arty)
7 | (synopsis "A wrapper for hardcaml_mips on the Arty A7 FPGA."))
8 |
9 | (version 1.0.0)
10 |
11 | (generate_opam_files true)
12 |
13 | (source
14 | (github askvortsov1/hardcaml-mips))
15 |
16 | (license MIT)
17 |
18 | (authors "Alexander Skvortsov" "Mayur Deshpande")
19 |
20 | (maintainers "sasha.skvortsov109@gmail.com")
21 |
22 | (homepage "https://ceramichacker.com/blog/category/hardcaml-mips")
23 |
--------------------------------------------------------------------------------
/arty/.Xil/hardcaml_arty_top_propImpl.xdc:
--------------------------------------------------------------------------------
1 | set_property SRC_FILE_INFO {cfile:/home/Programming/Projects/hardcaml-mips/arty/outputs/ips/design_1_clk_wiz_0_0/design_1_clk_wiz_0_0.xdc rfile:../outputs/ips/design_1_clk_wiz_0_0/design_1_clk_wiz_0_0.xdc id:1 order:EARLY scoped_inst:the_design_1_clk_wiz_0_0/inst} [current_design]
2 | current_instance the_design_1_clk_wiz_0_0/inst
3 | set_property src_info {type:SCOPED_XDC file:1 line:57 export:INPUT save:INPUT read:READ} [current_design]
4 | set_input_jitter [get_clocks -of_objects [get_ports clk_in1]] 0.100
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Hardcaml MIPS CPU
2 |
3 | Hi! We are Sasha Skvortsov and Mayur Deshpande. As a followup to a class project, we are designing a simple 5-stage MIPS CPU in OCaml via the [HardCaml](https://github.com/janestreet/hardcaml) library. You can read more about this project at the [CeramicHacker](https://ceramichacker.com/t/hardcaml-mips) blog.
4 |
5 | ## Code Structure
6 |
7 | There are 3 main components to this codebase:
8 |
9 | - In `lib`: source code for the MIPS CPU
10 | - In `test`: Unit and integration tests for the MIPS CPU
11 | - In the project root: a `main.ml` file that prints the design from `lib` into Verilog
12 |
13 | ## How to Use
14 |
15 | Coming Soon
16 |
--------------------------------------------------------------------------------
/lib/io/io_intf.ml:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 | open Hardcaml.Signal
3 |
4 | module type Io_intf = sig
5 | module I : sig
6 | type 'a t = {
7 | clock : 'a; [@bits 1]
8 | write_enable : 'a; [@bits 1]
9 | write_addr : 'a; [@bits 32]
10 | write_data : 'a; [@bits 32]
11 | read_enable : 'a; [@bits 1]
12 | read_addr : 'a; [@bits 32]
13 | }
14 | [@@deriving sexp_of, hardcaml]
15 | end
16 |
17 | module O : sig
18 | type 'a t = {
19 | io_busy : 'a; [@bits 1]
20 | read_data : 'a; [@bits 32]
21 | }
22 | [@@deriving sexp_of, hardcaml]
23 | end
24 |
25 | val circuit_impl : Scope.t -> t I.t -> t O.t
26 |
27 | val hierarchical : Scope.t -> t I.t -> t O.t
28 | end
29 |
--------------------------------------------------------------------------------
/hardcaml_mips.opam:
--------------------------------------------------------------------------------
1 | # This file is generated by dune, edit dune-project instead
2 | opam-version: "2.0"
3 | version: "1.0.0"
4 | synopsis: "A simple MIPS CPU learning project in Hardcaml."
5 | maintainer: ["sasha.skvortsov109@gmail.com"]
6 | authors: ["Alexander Skvortsov" "Mayur Deshpande"]
7 | license: "MIT"
8 | homepage: "https://ceramichacker.com/blog/category/hardcaml-mips"
9 | bug-reports: "https://github.com/askvortsov1/hardcaml-mips/issues"
10 | depends: [
11 | "dune" {>= "2.8"}
12 | "odoc" {with-doc}
13 | ]
14 | build: [
15 | ["dune" "subst"] {dev}
16 | [
17 | "dune"
18 | "build"
19 | "-p"
20 | name
21 | "-j"
22 | jobs
23 | "@install"
24 | "@runtest" {with-test}
25 | "@doc" {with-doc}
26 | ]
27 | ]
28 | dev-repo: "git+https://github.com/askvortsov1/hardcaml-mips.git"
29 |
--------------------------------------------------------------------------------
/arty/hardcaml_mips_arty.opam:
--------------------------------------------------------------------------------
1 | # This file is generated by dune, edit dune-project instead
2 | opam-version: "2.0"
3 | version: "1.0.0"
4 | synopsis: "A wrapper for hardcaml_mips on the Arty A7 FPGA."
5 | maintainer: ["sasha.skvortsov109@gmail.com"]
6 | authors: ["Alexander Skvortsov" "Mayur Deshpande"]
7 | license: "MIT"
8 | homepage: "https://ceramichacker.com/blog/category/hardcaml-mips"
9 | bug-reports: "https://github.com/askvortsov1/hardcaml-mips/issues"
10 | depends: [
11 | "dune" {>= "2.8"}
12 | "odoc" {with-doc}
13 | ]
14 | build: [
15 | ["dune" "subst"] {dev}
16 | [
17 | "dune"
18 | "build"
19 | "-p"
20 | name
21 | "-j"
22 | jobs
23 | "@install"
24 | "@runtest" {with-test}
25 | "@doc" {with-doc}
26 | ]
27 | ]
28 | dev-repo: "git+https://github.com/askvortsov1/hardcaml-mips.git"
29 |
--------------------------------------------------------------------------------
/arty/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: ../_build/default/arty/arty.exe
2 |
3 | ../_build/default/arty/arty.exe:
4 | dune build arty.exe
5 |
6 | hardcaml_arty_top.v: ../_build/default/arty/arty.exe
7 | $< >$@
8 |
9 | outputs/post_synth.dcp: synth.tcl hardcaml_arty_top.v
10 | vivado -nojournal -mode batch -source synth.tcl -log outputs/synth.log
11 |
12 | outputs/post_place.dcp: place.tcl outputs/post_synth.dcp
13 | vivado -nojournal -mode batch -source place.tcl -log outputs/place.log
14 |
15 | outputs/hardcaml_arty_top.bit outputs/post_route.dcp: route.tcl outputs/post_place.dcp
16 | vivado -nojournal -mode batch -source route.tcl -log outputs/route.log
17 | rm -f usage_statistics_webtalk.html usage_statistics_webtalk.xml
18 |
19 | make build:
20 | make outputs/hardcaml_arty_top.bit
21 |
22 | make prog:
23 | djtgcfg prog --file outputs/hardcaml_arty_top.bit -d Arty -i 0
24 |
25 | clean:
26 | rm -f outputs/*
27 |
--------------------------------------------------------------------------------
/lib/writeback/writeback.ml:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 | open Hardcaml.Signal
3 |
4 | module I = struct
5 | type 'a t = {
6 | sel_mem_for_reg_data : 'a;
7 | alu_result : 'a; [@bits 32]
8 | data_output : 'a; [@bits 32]
9 | }
10 | [@@deriving sexp_of, hardcaml]
11 | end
12 |
13 | module O = struct
14 | type 'a t = { writeback_data : 'a [@bits 32] } [@@deriving sexp_of, hardcaml]
15 | end
16 |
17 | let circuit_impl (_scope : Scope.t) (input : _ I.t) =
18 | let writeback_data =
19 | mux2 input.sel_mem_for_reg_data input.data_output input.alu_result
20 | in
21 | { O.writeback_data }
22 |
23 | let circuit_impl_exn scope input =
24 | let module W = Width_check.With_interface (I) (O) in
25 | W.check_widths (circuit_impl scope) input
26 |
27 | let hierarchical scope input =
28 | let module H = Hierarchy.In_scope (I) (O) in
29 | H.hierarchical ~scope ~name:"writeback" circuit_impl_exn input
30 |
--------------------------------------------------------------------------------
/lib/instruction_decode/stall_unit.ml:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 | open Hardcaml.Signal
3 |
4 | module I = struct
5 | type 'a t = {
6 | e_sel_mem_for_reg_data : 'a;
7 | rs : 'a; [@bits 5]
8 | rt : 'a; [@bits 5]
9 | e_dest: 'a; [@bits 5]
10 | }
11 | [@@deriving sexp_of, hardcaml]
12 | end
13 |
14 | module O = struct
15 | type 'a t = { stall_pc: 'a } [@@deriving sexp_of, hardcaml]
16 | end
17 |
18 | let circuit_impl (_scope : Scope.t) (input : _ I.t) =
19 | let lw_in_execute = input.e_sel_mem_for_reg_data in
20 | let uses_execute_output = ((input.rs ==: input.e_dest) |: (input.rt ==: input.e_dest)) in
21 | let stall_pc = lw_in_execute &: uses_execute_output in
22 |
23 | { O.stall_pc }
24 |
25 | let circuit_impl_exn scope input =
26 | let module W = Width_check.With_interface (I) (O) in
27 | W.check_widths (circuit_impl scope) input
28 |
29 | let hierarchical scope input =
30 | let module H = Hierarchy.In_scope (I) (O) in
31 | H.hierarchical ~scope ~name:"stall_unit" circuit_impl_exn input
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2021-Present Alexander Skvortsov, Mayur Deshpande
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/arty/synth.tcl:
--------------------------------------------------------------------------------
1 | set_param board.repoPaths "boards/"
2 |
3 | create_project -in_memory -part xc7a35ticsg324-1L
4 | set_property board_part digilentinc.com:arty-a7-35:part0:1.0 [current_project]
5 | set output_dir "./outputs"
6 |
7 | exec rm -rf outputs/ips
8 | exec cp -r ips/ outputs/ips
9 | read_ip -verbose outputs/ips/design_1_clk_wiz_0_0/design_1_clk_wiz_0_0.xci
10 |
11 | # TODO(fyquah): It is unfortunate that we need to comment this out by hand. Our
12 | # RTL generator should know that the thernet mac isn't used, and hence
13 | # shouldn't be read here. This can be fixed by generating tcl files.
14 | # read_ip -verbose ips/hardcaml_arty_tri_mode_ethernet_mac_0/hardcaml_arty_tri_mode_ethernet_mac_0.xci
15 | read_verilog hardcaml_arty_top.v
16 |
17 | upgrade_ip [get_ips]
18 | set_property generate_synth_checkpoint false [get_files outputs/ips/design_1_clk_wiz_0_0/design_1_clk_wiz_0_0.xci]
19 | # set_property generate_synth_checkpoint false [get_files ips/hardcaml_arty_tri_mode_ethernet_mac_0/hardcaml_arty_tri_mode_ethernet_mac_0.xci]
20 | generate_target all [get_ips]
21 | validate_ip [get_ips]
22 |
23 | synth_design -top hardcaml_arty_top
24 | write_checkpoint -force "${::output_dir}/post_synth.dcp"
25 |
--------------------------------------------------------------------------------
/lib/io/memory.ml:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 | open Hardcaml.Signal
3 |
4 | module I = struct
5 | type 'a t = {
6 | clock : 'a; [@bits 1]
7 | write_enable : 'a; [@bits 1]
8 | write_addr : 'a; [@bits 32]
9 | write_data : 'a; [@bits 32]
10 | read_enable : 'a; [@bits 1]
11 | read_addr : 'a; [@bits 32]
12 | }
13 | [@@deriving sexp_of, hardcaml]
14 | end
15 |
16 | module O = struct
17 | type 'a t = { io_busy : 'a; [@bits 1] read_data : 'a [@bits 32] }
18 | [@@deriving sexp_of, hardcaml]
19 | end
20 |
21 | let data_memory write_clock write_enable write_data write_addr read_addr =
22 | let write_port =
23 | { write_clock; write_address = write_addr; write_enable; write_data }
24 | in
25 | let mem =
26 | multiport_memory 512 ~write_ports:[| write_port |]
27 | ~read_addresses:[| read_addr |]
28 | in
29 | Array.get mem 0
30 |
31 | let circuit_impl (_scope : Scope.t) (input : _ I.t) =
32 | let read_data =
33 | data_memory input.clock input.write_enable input.write_data input.write_addr
34 | input.read_addr
35 | in
36 | { O.read_data; io_busy = of_bool false }
37 |
38 | let hierarchical scope input =
39 | let module H = Hierarchy.In_scope (I) (O) in
40 | H.hierarchical ~scope ~name:"memory" circuit_impl input
41 |
--------------------------------------------------------------------------------
/interactive.ml:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 | open Hardcaml_waveterm
3 | open Mips.Cpu
4 |
5 | module Simulator = Cyclesim.With_interface (I) (O)
6 |
7 | let testbench n =
8 | let scope = Scope.create ~auto_label_hierarchical_ports:true ~flatten_design:true () in
9 | let program =
10 | Mips.Program.create
11 | [
12 | "3C08FFFF" (* lui t0 0xFFFF *);
13 | "3508FFFF" (* ori t0 t0 0xFFFF *);
14 | "214A0008" (* addi $t2 $t2 0x0008 *);
15 | "216B0004" (* addi $t3 $t3 0x0004 *);
16 | "8D0C0000" (* lw $t4 0($t0) *);
17 | "000C6820" (* add $t5 $zero $t4 *);
18 | "000C6820" (* add $t5 $zero $t4 *);
19 | "000C6820" (* add $t5 $zero $t4 *);
20 | "000C6820" (* add $t5 $zero $t4 *);
21 | "000C6820" (* add $t5 $zero $t4 *);
22 | "214A0008" (* addi $t2 $t3 0x0008 *);
23 | "216B0006" (* addi $t3 $t2 0x0006 *);
24 | ]
25 | in
26 | let sim = Simulator.create ~config:Cyclesim.Config.trace_all (circuit_impl program scope) in
27 | let waves, sim = Waveform.create sim in
28 |
29 | for _i = 0 to n do
30 | Cyclesim.cycle sim
31 | done;
32 |
33 | waves
34 |
35 | let () =
36 | let waves = testbench 15 in
37 | Hardcaml_waveterm_interactive.run ~wave_width:5 ~signals_width:30 waves
--------------------------------------------------------------------------------
/lib/instruction_execute/instruction_execute.ml:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 | open Hardcaml.Signal
3 |
4 | module I = struct
5 | type 'a t = {
6 | alu_a : 'a; [@bits 32]
7 | alu_b : 'a; [@bits 32]
8 | imm : 'a; [@bits 32]
9 | sel_shift_for_alu: 'a;
10 | sel_imm_for_alu: 'a;
11 | alu_control : 'a; [@bits (width Control_unit.Alu_ops.default)]
12 | jal : 'a;
13 | prev2_pc : 'a; [@bits 32]
14 | }
15 | [@@deriving sexp_of, hardcaml]
16 | end
17 |
18 | module O = struct
19 | type 'a t = { alu_result : 'a [@bits 32] } [@@deriving sexp_of, hardcaml]
20 | end
21 |
22 | let circuit_impl (scope : Scope.t) (input : _ I.t) =
23 | let shift_amount = uresize input.imm.:[10, 6] 32 in
24 | let arg_a = mux2 input.sel_shift_for_alu shift_amount input.alu_a in
25 | let arg_b = mux2 input.sel_imm_for_alu input.imm input.alu_b in
26 | let alu = Alu.hierarchical scope { Alu.I.arg_a; arg_b; alu_control = input.alu_control} in
27 | let alu_result = mux2 input.jal (input.prev2_pc +:. 8) alu.result in
28 | { O.alu_result }
29 |
30 | let circuit_impl_exn scope input =
31 | let module W = Width_check.With_interface (I) (O) in
32 | W.check_widths (circuit_impl scope) input
33 |
34 | let hierarchical scope input =
35 | let module H = Hierarchy.In_scope (I) (O) in
36 | H.hierarchical ~scope ~name:"instruction_execute" circuit_impl_exn input
37 |
--------------------------------------------------------------------------------
/lib/io/uart.mli:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 | open Hardcaml.Signal
3 |
4 | module Word_with_valid : sig
5 | include Hardcaml.Interface.S with type 'a t = 'a With_valid.t
6 | end
7 |
8 | val cycles_per_packet : int
9 |
10 | module Rx_buffer : sig
11 | val create :
12 | clock:Signal.t ->
13 | read_enable:Signal.t ->
14 | Signal.t Hardcaml_arty.Uart.Byte_with_valid.t ->
15 | (Signal.t Word_with_valid.t * Signal.t)
16 | end
17 |
18 | module Tx_buffer : sig
19 | val create :
20 | clock:Signal.t ->
21 | Signal.t Word_with_valid.t ->
22 | (Signal.t Hardcaml_arty.Uart.Byte_with_valid.t * Signal.t)
23 | end
24 |
25 | module I : sig
26 | type 'a t = {
27 | clock : 'a; [@bits 1]
28 | write_enable : 'a; [@bits 1]
29 | write_addr : 'a; [@bits 32]
30 | write_data : 'a; [@bits 32]
31 | read_enable : 'a; [@bits 1]
32 | read_addr : 'a; [@bits 32]
33 | uart_rx : 'a Hardcaml_arty.Uart.Byte_with_valid.t;[@rtlprefix "rx_"]
34 | }
35 | [@@deriving sexp_of, hardcaml]
36 | end
37 |
38 | module O : sig
39 | type 'a t = {
40 | io_busy : 'a; [@bits 1]
41 | read_data : 'a; [@bits 32]
42 | uart_tx : 'a Hardcaml_arty.Uart.Byte_with_valid.t;[@rtlprefix "tx_"]
43 | }
44 | [@@deriving sexp_of, hardcaml]
45 | end
46 |
47 | val circuit_impl : Scope.t -> t I.t -> t O.t
48 |
49 | val hierarchical : Scope.t -> t I.t -> t O.t
--------------------------------------------------------------------------------
/lib/instruction_fetch/gen_next_pc.ml:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 | open Hardcaml.Signal
3 |
4 | module I = struct
5 | type 'a t = {
6 | pc : 'a; [@bits 32]
7 | prev_pc : 'a; [@bits 32]
8 | alu_a : 'a; [@bits 32]
9 | alu_b : 'a; [@bits 32]
10 | addr: 'a; [@bits 26]
11 | se_imm: 'a; [@bits 32]
12 | pc_sel: 'a Control_unit.Pc_sel.Binary.t;
13 | }
14 |
15 | [@@deriving sexp_of, hardcaml]
16 | end
17 |
18 | module O = struct
19 | type 'a t = { next_pc : 'a [@bits 32] } [@@deriving sexp_of, hardcaml]
20 | end
21 |
22 |
23 | let circuit_impl (_scope : Scope.t) (input : _ I.t) =
24 | let open Control_unit.Pc_sel.Enum in
25 | let pc_incr = input.pc +:. 4 in
26 | let branch_addr = input.prev_pc +:. 4 +: (sll input.se_imm 2) in
27 | let next_pc = Control_unit.Pc_sel.Binary.match_ (module Signal) input.pc_sel
28 | [
29 | Pc_incr, pc_incr;
30 | Jump_addr, input.pc.:[31, 28] @: (sll (uresize input.addr 28) 2);
31 | Jump_reg, input.alu_a;
32 | Branch_eq, mux2 (input.alu_a ==: input.alu_b) branch_addr pc_incr;
33 | Branch_neq, mux2 (input.alu_a <>: input.alu_b) branch_addr pc_incr;
34 | ] in
35 |
36 | { O.next_pc }
37 |
38 | let circuit_impl_exn scope input =
39 | let module W = Width_check.With_interface (I) (O) in
40 | W.check_widths (circuit_impl scope) input
41 |
42 | let hierarchical scope input =
43 | let module H = Hierarchy.In_scope (I) (O) in
44 | H.hierarchical ~scope ~name:"gen_next_pc" circuit_impl_exn input
45 |
46 |
47 |
--------------------------------------------------------------------------------
/lib/instruction_execute/alu.ml:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 | open Hardcaml.Signal
3 |
4 | module I = struct
5 | type 'a t = {
6 | arg_a : 'a; [@bits 32]
7 | arg_b : 'a; [@bits 32]
8 | alu_control : 'a; [@bits (width Control_unit.Alu_ops.default)]
9 | }
10 | [@@deriving sexp_of, hardcaml]
11 | end
12 |
13 | module O = struct
14 | type 'a t = { result : 'a [@bits 32] } [@@deriving sexp_of, hardcaml]
15 | end
16 |
17 | let circuit_impl (_scope : Scope.t) (input : _ I.t) =
18 | let result = Always.Variable.wire ~default:(of_string "32'b0") in
19 | let module Op = Control_unit.Alu_ops in
20 | let a = input.arg_a in
21 | let b = input.arg_b in
22 | Always.(
23 | compile
24 | [
25 | switch input.alu_control
26 | [
27 | (Op.add, [ result <-- a +: b ]);
28 | (Op.addu, [ result <-- a +: b ]);
29 | (Op.and_, [ result <-- (a &: b) ]);
30 | (Op.lui, [ result <-- b.:[(15, 0)] @: of_string "16'h0" ]);
31 | (Op.or_, [ result <-- (a |: b) ]);
32 | (Op.slt, [ result <-- uresize (a <: b) 32 ]);
33 | (Op.sltu, [ result <-- uresize (a <+ b) 32 ]);
34 | (Op.sll, [ result <-- log_shift sll b a ]);
35 | (Op.sra, [ result <-- log_shift sra b a ]);
36 | (Op.srl, [ result <-- log_shift srl b a ]);
37 | (Op.sub, [ result <-- a -: b ]);
38 | (Op.subu, [ result <-- a -: b ]);
39 | (Op.xor, [ result <-- a ^: b ]);
40 | ];
41 | ]);
42 |
43 | { O.result = Always.Variable.value result }
44 |
45 | let circuit_impl_exn scope input =
46 | let module W = Width_check.With_interface (I) (O) in
47 | W.check_widths (circuit_impl scope) input
48 |
49 | let hierarchical scope input =
50 | let module H = Hierarchy.In_scope (I) (O) in
51 | H.hierarchical ~scope ~name:"alu" circuit_impl_exn input
52 |
--------------------------------------------------------------------------------
/lib/instruction_fetch/instruction_fetch.ml:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 | open Hardcaml.Signal
3 |
4 | module I = struct
5 | type 'a t = { pc : 'a [@bits 32] } [@@deriving sexp_of, hardcaml]
6 | end
7 |
8 | module O = struct
9 | type 'a t = { instruction : 'a; [@bits 32] }
10 | [@@deriving sexp_of, hardcaml]
11 | end
12 |
13 | (* In an actual computer, instruction memory would be actual memory,
14 | * and we would use Hardcaml's `multiport_memory` primitive to implement it.
15 | *
16 | * Unfortunately, that primitive doesn't support initial values, so testing would
17 | * require either a complex sequence of `reset` logic or a physical RAM device.
18 | *
19 | * The former would be messy and the latter beyond the scope of this project,
20 | * but we still don't want to hardcode a particular program as part of the design.
21 | * Instead, to keep things simple, we consider the program to be an input to our Hardcaml CPU.
22 | *)
23 | let instruction_memory program address =
24 | (* When the selector > length inputs, Hardcaml's mux will just repeat the last element.
25 | * To avoid unexpected effects if `pc` goes beyond the length of our program,
26 | * we append a noop to our program. *)
27 | let program_signals = Program.to_signals program @ [ of_string "32'h0" ] in
28 | mux address program_signals
29 |
30 | let circuit_impl (program : Program.t) (_scope : Scope.t) (input : _ I.t) =
31 | let address = srl input.pc 2 in
32 | let instruction = instruction_memory program address in
33 | { O.instruction }
34 |
35 | let circuit_impl_exn program scope input =
36 | let module W = Width_check.With_interface (I) (O) in
37 | W.check_widths (circuit_impl program scope) input
38 |
39 | let hierarchical program scope input =
40 | let module H = Hierarchy.In_scope (I) (O) in
41 | H.hierarchical ~scope ~name:"instruction_fetch" (circuit_impl_exn program)
42 | input
43 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | # This is a basic workflow to help you get started with Actions
2 |
3 | name: CI
4 |
5 | # Controls when the action will run.
6 | on:
7 | # Triggers the workflow on push or pull request events but only for the main branch
8 | push:
9 | branches: [ main ]
10 | pull_request:
11 | branches: [ main ]
12 |
13 | # Allows you to run this workflow manually from the Actions tab
14 | workflow_dispatch:
15 |
16 |
17 |
18 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel
19 | jobs:
20 | # This workflow contains a single job called "build"
21 | build:
22 | strategy:
23 | fail-fast: false
24 | matrix:
25 | os:
26 | - ubuntu-latest
27 | ocaml-compiler:
28 | - 4.13.x
29 |
30 | runs-on: ${{ matrix.os }}
31 |
32 | # Steps represent a sequence of tasks that will be executed as part of the job
33 | steps:
34 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
35 | - uses: actions/checkout@v2
36 |
37 | - name: Set up OCaml
38 | uses: ocaml/setup-ocaml@v2
39 | with:
40 | ocaml-compiler: ${{ matrix.ocaml-compiler }}
41 |
42 | - name: Set up source repos
43 | run: |
44 | opam repo add janestreet-bleeding https://ocaml.janestreet.com/opam-repository
45 | opam repo add janestreet-bleeding-external https://github.com/janestreet/opam-repository.git#external-packages
46 | eval $(opam env)
47 |
48 | - name: Install Deps
49 | run: |
50 | opam install dune core hardcaml hardcaml_waveterm ppx_deriving_hardcaml ppx_expect ppx_jane
51 | opam pin add https://github.com/askvortsov1/hardcaml_arty.git#as/make-installable --yes
52 | eval $(opam env)
53 |
54 | - name: Build
55 | run: opam exec -- dune build
56 |
57 | - name: Testing
58 | run: opam exec -- dune test
59 |
--------------------------------------------------------------------------------
/arty/place.tcl:
--------------------------------------------------------------------------------
1 | set_param board.repoPaths "boards/"
2 | set output_dir "outputs/"
3 |
4 | open_checkpoint $output_dir/post_synth.dcp
5 |
6 | ########################
7 | # Various pin placements
8 | ########################
9 |
10 | proc bind_port_to_pin { port_name pin_name } {
11 | set port [get_ports "$port_name"]
12 | set pin [get_board_part_pins "$pin_name"]
13 | set loc [get_property LOC $pin]
14 | set iostandard [get_property IOSTANDARD $pin]
15 |
16 | set_property PACKAGE_PIN $loc $port
17 | set_property IOSTANDARD $iostandard $port
18 | }
19 |
20 | proc bind_ports_vector_to_pins {port_format pin_format n} {
21 | for { set i 0 } { $i < $n } { incr i } {
22 | set port_name [format $port_format $i]
23 | set pin_name [format $pin_format $i]
24 | bind_port_to_pin $port_name $pin_name
25 | }
26 | }
27 |
28 | bind_ports_vector_to_pins "led_4bits\[%d\]" "led_4bits_tri_o_%d" 4
29 | bind_ports_vector_to_pins "led_rgb\[%d\]" "rgb_led_tri_o_%d" 12
30 | bind_ports_vector_to_pins "push_buttons_4bits\[%d\]" "push_buttons_4bits_tri_i_%d" 4
31 | bind_port_to_pin "usb_uart_rx" "usb_uart_rxd"
32 | bind_port_to_pin "usb_uart_tx" "usb_uart_txd"
33 | bind_port_to_pin "sys_clock" "clk"
34 | bind_port_to_pin "reset" "reset"
35 |
36 | bind_ports_vector_to_pins "eth_mii_rxd\[%d\]" "eth_rxd_%d" 4
37 | bind_port_to_pin "eth_mii_rx_er" "eth_rx_er"
38 | bind_port_to_pin "eth_mii_rx_dv" "eth_rx_dv"
39 | bind_port_to_pin "eth_mii_rx_clk" "eth_rx_clk"
40 | bind_port_to_pin "eth_mii_tx_clk" "eth_tx_clk"
41 |
42 | bind_port_to_pin "eth_mii_tx_en" "eth_tx_en"
43 | bind_ports_vector_to_pins "eth_mii_txd\[%d\]" "eth_txd_%d" 4
44 |
45 | bind_port_to_pin "mdc" "eth_mdc"
46 |
47 | opt_design
48 | place_design
49 | phys_opt_design
50 |
51 | write_checkpoint -force $output_dir/post_place
52 | report_timing_summary -file $output_dir/post_place_timing_summary.rpt
53 |
--------------------------------------------------------------------------------
/lib/program.ml:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 | open Hardcaml.Signal
3 |
4 | type t = Signal.t list
5 |
6 | let create program =
7 | program
8 | |> List.map (fun str -> "32'h" ^ str)
9 | |> List.map of_string
10 |
11 | let to_signals program = program
12 |
13 | let sample_strings =
14 | [
15 | "3c010000"; (* (00) main: lui $1, 0 *)
16 | "34240050"; (* (04) ori $4, $1, 50 *)
17 | "0c00001b"; (* (08) call: jal sum *)
18 | "20050004"; (* (0c) dslot1: addi $5, $0, 4 *)
19 | "ac820000"; (* (10) return: sw $2, 0($4) *)
20 | "8c890000"; (* (14) lw $9, 0($4) *)
21 | "01244022"; (* (18) sub $8, $9, $4 *)
22 | "20050003"; (* (1c) addi $5, $0, 3 *)
23 | "20a5ffff"; (* (20) loop2: addi $5, $5, -1 *)
24 | "34a8ffff"; (* (24) ori $8, $5, 0xffff *)
25 | "39085555"; (* (28) xori $8, $8, 0x5555 *)
26 | "2009ffff"; (* (2c) addi $9, $0, -1 *)
27 | "312affff"; (* (30) andi $10,$9,0xffff *)
28 | "01493025"; (* (34) or $6, $10, $9 *)
29 | "01494026"; (* (38) xor $8, $10, $9 *)
30 | "01463824"; (* (3c) and $7, $10, $6 *)
31 | "10a00003"; (* (40) beq $5, $0, shift *)
32 | "00000000"; (* (44) dslot2: nop *)
33 | "08000008"; (* (48) j loop2 *)
34 | "00000000"; (* (4c) dslot3: nop *)
35 | "2005ffff"; (* (50) shift: addi $5, $0, -1 *)
36 | "000543c0"; (* (54) sll $8, $5, 15 *)
37 | "00084400"; (* (58) sll $8, $8, 16 *)
38 | "00084403"; (* (5c) sra $8, $8, 16 *)
39 | "000843c2"; (* (60) srl $8, $8, 15 *)
40 | "08000019"; (* (64) finish: j finish *)
41 | "00000000"; (* (68) dslot4: nop *)
42 | "00004020"; (* (6c) sum: add $8, $0, $0 *)
43 | "8c890000"; (* (70) loop: lw $9, 0($4) *)
44 | "01094020"; (* (74) stall: add $8, $8, $9 *)
45 | "20a5ffff"; (* (78) addi $5, $5, -1 *)
46 | "14a0fffc"; (* (7c) bne $5, $0, loop *)
47 | "20840004"; (* (80) dslot5: addi $4, $4, 4 *)
48 | "03e00008"; (* (84) jr $31 *)
49 | "00081000"; (* (88) dslot6: sll $2, $8, 0 *)
50 | ]
51 |
52 | let sample = create sample_strings
53 |
--------------------------------------------------------------------------------
/arty/arty.ml:
--------------------------------------------------------------------------------
1 | open Hardcaml.Signal
2 | module UA = Hardcaml_arty.User_application
3 |
4 | let rgb_off =
5 | {
6 | Hardcaml_arty.User_application.Led_rgb.r = of_bool false;
7 | g = of_bool false;
8 | b = of_bool false;
9 | }
10 |
11 | let sample =
12 | Mips.Program.create
13 | [
14 | "3C10FFFF" (* (0) lui $s0 0xFFFF *);
15 | "3610FFFE" (* (4) ori $s0 $s0 0xFFFE *);
16 | "20110030" (* (8) addi $s1 $zero 0x0030 *);
17 | "356B3A20" (* (C) ori $t3 $t3 0x3A20 *);
18 | "AE0B0000" (* (10) sw $t3 0x0000 $s0 *);
19 | "8E080000" (* (14) lw $t0 0x0000 $s0 *);
20 | "AE080000" (* (18) sw $t0 0x0000 $s0 *);
21 | "3C0B0A00" (* (1C) lui $t3 0x0A00 *);
22 | "356B0000" (* (20) ori $t3 $t3 0x0000 *);
23 | "AE0B0000" (* (24) sw $t3 0x0000 $s0 *);
24 | "3C0B2332" (* (28) lui $t3 0x2332 *);
25 | "356B3A20" (* (2C) ori $t3 $t3 0x3A20 *);
26 | "AE0B0000" (* (30) sw $t3 0x0000 $s0 *);
27 | "8E090000" (* (34) lw $t1 0x0000 $s0 *);
28 | "AE090000" (* (38) sw $t1 0x0000 $s0 *);
29 | "00084602" (* (3C) srl $t0 $t0 0x0018 *);
30 | "00094E02" (* (40) srl $t1 $t1 0x0018 *);
31 | "01114022" (* (44) sub $t0 $t0 $s1 *);
32 | "01314822" (* (48) sub $t1 $t1 $s1 *);
33 | "01095020" (* (4C) add $t2 $t0 $t1 *);
34 | "01515020" (* (50) add $t2 $t2 $s1 *);
35 | "3C0B0A00" (* (54) lui $t3 0x0A00 *);
36 | "356B0000" (* (58) ori $t3 $t3 0x0000 *);
37 | "AE0B0000" (* (5C) sw $t3 0x0000 $s0 *);
38 | "3C0B414E" (* (60) lui $t3 0x414E *);
39 | "356B533A" (* (64) ori $t3 $t3 0x533A *);
40 | "AE0B0000" (* (68) sw $t3 0x0000 $s0 *);
41 | "AE0A0000" (* (6C) sw $t2 0x0000 $s0 *);
42 | "3C0B0A00" (* (70) lui $t3 0x0A00 *);
43 | "356B0000" (* (74) ori $t3 $t3 0x0000 *);
44 | "AE0B0000" (* (78) sw $t3 0x0000 $s0 *);
45 | ]
46 |
47 | let circuit program scope input =
48 | let cpu = Mips.Cpu.circuit_impl program scope input in
49 | {
50 | UA.O.uart_tx = cpu.uart_tx;
51 | ethernet = cpu.ethernet;
52 | led_4bits = cpu.writeback_pc.:[(31, 28)];
53 | led_rgb = [ rgb_off; rgb_off; rgb_off; rgb_off ];
54 | }
55 |
56 | let () =
57 | Hardcaml_arty.Rtl_generator.generate ~instantiate_ethernet_mac:false
58 | (circuit sample) (To_channel Stdio.stdout)
59 |
--------------------------------------------------------------------------------
/lib/instruction_decode/forwarding_unit.ml:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 | open Hardcaml.Signal
3 |
4 | module Data_options = struct
5 | type 'a t = {
6 | reg_value : 'a; [@bits 32]
7 | e_alu_output : 'a; [@bits 32]
8 | m_alu_output : 'a; [@bits 32]
9 | m_data_output : 'a; [@bits 32]
10 | }
11 | [@@deriving sexp_of, hardcaml]
12 | end
13 |
14 | module Controls = struct
15 | type 'a t = {
16 | e_stalled : 'a;
17 | e_sel_mem_for_reg_data : 'a;
18 | m_sel_mem_for_reg_data : 'a;
19 | e_reg_write_enable : 'a;
20 | m_reg_write_enable : 'a;
21 | }
22 | [@@deriving sexp_of, hardcaml]
23 | end
24 |
25 | module I = struct
26 | type 'a t = {
27 | options : 'a Data_options.t;
28 | controls : 'a Controls.t;
29 | source : 'a; [@bits 5]
30 | e_dest : 'a; [@bits 5]
31 | m_dest : 'a; [@bits 5]
32 | }
33 | [@@deriving sexp_of, hardcaml]
34 | end
35 |
36 | module O = struct
37 | type 'a t = { forward_data : 'a [@bits 32] } [@@deriving sexp_of, hardcaml]
38 | end
39 |
40 | let circuit_impl (_scope : Scope.t) (input : _ I.t) =
41 | let opt = input.options in
42 | let ctrl = input.controls in
43 | let forward_data =
44 | priority_select_with_default ~default:opt.reg_value
45 | [
46 | {
47 | With_valid.valid =
48 | (* The last instruction wrote to this register, and was NOT a lw, and WAS NOT stalled. *)
49 | ctrl.e_reg_write_enable
50 | &: (input.source ==: input.e_dest)
51 | &: ~:(ctrl.e_sel_mem_for_reg_data)
52 | &: ~:(ctrl.e_stalled);
53 | value = opt.e_alu_output;
54 | };
55 | {
56 | With_valid.valid =
57 | (* The 2nd to last instruction wrote to this register, and was an lw. *)
58 | ctrl.m_reg_write_enable
59 | &: (input.source ==: input.m_dest)
60 | &: ctrl.m_sel_mem_for_reg_data;
61 | value = opt.m_data_output;
62 | };
63 | {
64 | (* The 2nd to last instruction wrote to this register *)
65 | With_valid.valid =
66 | ctrl.m_reg_write_enable &: (input.source ==: input.m_dest);
67 | value = opt.m_alu_output;
68 | };
69 | ]
70 | in
71 | { O.forward_data }
72 |
73 | let circuit_impl_exn scope input =
74 | let module W = Width_check.With_interface (I) (O) in
75 | W.check_widths (circuit_impl scope) input
76 |
77 | let hierarchical scope input =
78 | let module H = Hierarchy.In_scope (I) (O) in
79 | H.hierarchical ~scope ~name:"forwarding_unit" circuit_impl_exn input
80 |
--------------------------------------------------------------------------------
/arty/ips/design_1_clk_wiz_0_0/design_1_clk_wiz_0_0_ooc.xdc:
--------------------------------------------------------------------------------
1 |
2 | # file: design_1_clk_wiz_0_0_ooc.xdc
3 | #
4 | # (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved.
5 | #
6 | # This file contains confidential and proprietary information
7 | # of Xilinx, Inc. and is protected under U.S. and
8 | # international copyright and other intellectual property
9 | # laws.
10 | #
11 | # DISCLAIMER
12 | # This disclaimer is not a license and does not grant any
13 | # rights to the materials distributed herewith. Except as
14 | # otherwise provided in a valid license issued to you by
15 | # Xilinx, and to the maximum extent permitted by applicable
16 | # law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
17 | # WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
18 | # AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
19 | # BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
20 | # INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
21 | # (2) Xilinx shall not be liable (whether in contract or tort,
22 | # including negligence, or under any other theory of
23 | # liability) for any loss or damage of any kind or nature
24 | # related to, arising under or in connection with these
25 | # materials, including for any direct, or any indirect,
26 | # special, incidental, or consequential loss or damage
27 | # (including loss of data, profits, goodwill, or any type of
28 | # loss or damage suffered as a result of any action brought
29 | # by a third party) even if such damage or loss was
30 | # reasonably foreseeable or Xilinx had been advised of the
31 | # possibility of the same.
32 | #
33 | # CRITICAL APPLICATIONS
34 | # Xilinx products are not designed or intended to be fail-
35 | # safe, or for use in any application requiring fail-safe
36 | # performance, such as life-support or safety devices or
37 | # systems, Class III medical devices, nuclear facilities,
38 | # applications related to the deployment of airbags, or any
39 | # other applications that could lead to death, personal
40 | # injury, or severe property or environmental damage
41 | # (individually and collectively, "Critical
42 | # Applications"). Customer assumes the sole risk and
43 | # liability of any use of Xilinx products in Critical
44 | # Applications, subject only to applicable laws and
45 | # regulations governing limitations on product liability.
46 | #
47 | # THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
48 | # PART OF THIS FILE AT ALL TIMES.
49 | #
50 |
51 | #################
52 | #DEFAULT CLOCK CONSTRAINTS
53 |
54 | ############################################################
55 | # Clock Period Constraints #
56 | ############################################################
57 | #create_clock -period 10.000 [get_ports clk_in1]
58 |
59 |
--------------------------------------------------------------------------------
/arty/ips/design_1_clk_wiz_0_0/design_1_clk_wiz_0_0.xdc:
--------------------------------------------------------------------------------
1 |
2 | # file: design_1_clk_wiz_0_0.xdc
3 | #
4 | # (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved.
5 | #
6 | # This file contains confidential and proprietary information
7 | # of Xilinx, Inc. and is protected under U.S. and
8 | # international copyright and other intellectual property
9 | # laws.
10 | #
11 | # DISCLAIMER
12 | # This disclaimer is not a license and does not grant any
13 | # rights to the materials distributed herewith. Except as
14 | # otherwise provided in a valid license issued to you by
15 | # Xilinx, and to the maximum extent permitted by applicable
16 | # law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
17 | # WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
18 | # AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
19 | # BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
20 | # INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
21 | # (2) Xilinx shall not be liable (whether in contract or tort,
22 | # including negligence, or under any other theory of
23 | # liability) for any loss or damage of any kind or nature
24 | # related to, arising under or in connection with these
25 | # materials, including for any direct, or any indirect,
26 | # special, incidental, or consequential loss or damage
27 | # (including loss of data, profits, goodwill, or any type of
28 | # loss or damage suffered as a result of any action brought
29 | # by a third party) even if such damage or loss was
30 | # reasonably foreseeable or Xilinx had been advised of the
31 | # possibility of the same.
32 | #
33 | # CRITICAL APPLICATIONS
34 | # Xilinx products are not designed or intended to be fail-
35 | # safe, or for use in any application requiring fail-safe
36 | # performance, such as life-support or safety devices or
37 | # systems, Class III medical devices, nuclear facilities,
38 | # applications related to the deployment of airbags, or any
39 | # other applications that could lead to death, personal
40 | # injury, or severe property or environmental damage
41 | # (individually and collectively, "Critical
42 | # Applications"). Customer assumes the sole risk and
43 | # liability of any use of Xilinx products in Critical
44 | # Applications, subject only to applicable laws and
45 | # regulations governing limitations on product liability.
46 | #
47 | # THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
48 | # PART OF THIS FILE AT ALL TIMES.
49 | #
50 |
51 | # Input clock periods. These duplicate the values entered for the
52 | # input clocks. You can use these to time your system. If required
53 | # commented constraints can be used in the top level xdc
54 | #----------------------------------------------------------------
55 | # Connect to input port when clock capable pin is selected for input
56 | create_clock -period 10.000 [get_ports clk_in1]
57 | set_input_jitter [get_clocks -of_objects [get_ports clk_in1]] 0.100
58 |
59 |
60 | set_property PHASESHIFT_MODE WAVEFORM [get_cells -hierarchical *adv*]
61 |
--------------------------------------------------------------------------------
/lib/io/delay_test_io.ml:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 | open Hardcaml.Signal
3 |
4 | (* Sample config for testing. *)
5 | let sample_read_delay = 2
6 | let sample_write_delay = 4
7 | let sample_read_data = of_int ~width:32 30
8 |
9 | module I = struct
10 | type 'a t = {
11 | clock : 'a; [@bits 1]
12 | write_enable : 'a; [@bits 1]
13 | write_addr : 'a; [@bits 32]
14 | write_data : 'a; [@bits 32]
15 | read_enable : 'a; [@bits 1]
16 | read_addr : 'a; [@bits 32]
17 | }
18 | [@@deriving sexp_of, hardcaml]
19 | end
20 |
21 | module O = struct
22 | type 'a t = { io_busy : 'a; [@bits 1] read_data : 'a [@bits 32] }
23 | [@@deriving sexp_of, hardcaml]
24 | end
25 |
26 | module States = struct
27 | type t = Not_stalling | Stalling | Done_stalling
28 | [@@deriving sexp_of, compare, enumerate]
29 | end
30 |
31 | let stall_sm ~clock ~stall_cycles ?(done_output = of_int ~width:32 0)
32 | should_stall =
33 | let width = Base.Int.ceil_log2 stall_cycles in
34 |
35 | (* One cycle is taken while switching into the Stalling state.
36 | * The other is taken while switching out of it.
37 | *)
38 | let stall_cycles_sig = of_int ~width (stall_cycles - 2) in
39 | let r = Reg_spec.create ~clock () in
40 | let sm = Always.State_machine.create (module States) ~enable:vdd r in
41 | let remaining_cycles = Always.Variable.reg r ~enable:vdd ~width in
42 | Always.(
43 | compile
44 | [
45 | sm.switch
46 | [
47 | ( Not_stalling,
48 | [
49 | when_ should_stall
50 | [
51 | sm.set_next Stalling; remaining_cycles <-- stall_cycles_sig;
52 | ];
53 | ] );
54 | ( Stalling,
55 | [
56 | remaining_cycles <-- remaining_cycles.value -:. 1;
57 | when_
58 | (remaining_cycles.value <=:. 0)
59 | [
60 | sm.set_next Done_stalling;
61 | remaining_cycles <-- stall_cycles_sig;
62 | ];
63 | ] );
64 | (Done_stalling, [ sm.set_next Not_stalling ]);
65 | ];
66 | ]);
67 | (* If an I/O operation was just initiated, we are always stalling regardless of the state. *)
68 | let busy = should_stall |: sm.is Stalling &: ~:(sm.is Done_stalling) in
69 | let output = mux2 (sm.is Done_stalling) done_output (of_int ~width:32 0) in
70 | (busy, output)
71 |
72 | let circuit_impl (_scope : Scope.t) (input : _ I.t) =
73 | let write_busy, _ =
74 | stall_sm ~clock:input.clock ~stall_cycles:sample_write_delay
75 | input.write_enable
76 | in
77 | let read_busy, read_data =
78 | stall_sm ~clock:input.clock ~stall_cycles:sample_read_delay
79 | ~done_output:sample_read_data input.read_enable
80 | in
81 | let io_busy = write_busy |: read_busy in
82 | { O.read_data; io_busy }
83 |
84 | let hierarchical scope input =
85 | let module H = Hierarchy.In_scope (I) (O) in
86 | H.hierarchical ~scope ~name:"delay_test_io" circuit_impl input
87 |
--------------------------------------------------------------------------------
/test/instruction_fetch/test_instruction_fetch.ml:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 | open Hardcaml_waveterm
3 | open Mips.Instruction_fetch
4 | module Simulator = Cyclesim.With_interface (I) (O)
5 |
6 | (* Arbitrary values, these don't map to actual instructions. *)
7 | let program = Mips.Program.create [ "00000008"; "00000001"; "99999999" ]
8 |
9 | let testbench () =
10 | let scope = Scope.create ~flatten_design:true () in
11 | let sim = Simulator.create (circuit_impl_exn program scope) in
12 | let waves, sim = Waveform.create sim in
13 | let inputs = Cyclesim.inputs sim in
14 |
15 | let step ~pc =
16 | inputs.pc := Bits.of_string pc;
17 | Cyclesim.cycle sim
18 | in
19 |
20 | step ~pc:"32'h00000000";
21 | step ~pc:"32'h00000001";
22 | (* Not an increment of 4, so should get instruction rounded down *)
23 | step ~pc:"32'h00000004";
24 | step ~pc:"32'h00000008";
25 | step ~pc:"32'h0000000C";
26 | (* There are only 3 instructions, so it should return a no-op *)
27 | step ~pc:"32'h00000000";
28 |
29 | waves
30 |
31 | let%expect_test "fetches appropriate instructions, increments PC by 4 correctly"
32 | =
33 | let waves = testbench () in
34 | Waveform.print ~wave_width:4 ~display_width:90 waves;
35 | [%expect
36 | {|
37 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐
38 | │ ││──────────┬─────────┬─────────┬─────────┬─────────┬───────── │
39 | │pc ││ 00000000 │00000001 │00000004 │00000008 │0000000C │00000000 │
40 | │ ││──────────┴─────────┴─────────┴─────────┴─────────┴───────── │
41 | │ ││────────────────────┬─────────┬─────────┬─────────┬───────── │
42 | │instruction ││ 00000008 │00000001 │99999999 │00000000 │00000008 │
43 | │ ││────────────────────┴─────────┴─────────┴─────────┴───────── │
44 | │ ││ │
45 | │ ││ │
46 | │ ││ │
47 | │ ││ │
48 | │ ││ │
49 | │ ││ │
50 | │ ││ │
51 | │ ││ │
52 | │ ││ │
53 | │ ││ │
54 | │ ││ │
55 | │ ││ │
56 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘
57 | |}]
58 |
--------------------------------------------------------------------------------
/test/test_writeback/test_writeback.ml:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 | open Hardcaml_waveterm
3 | open Mips.Writeback
4 | module Simulator = Cyclesim.With_interface (I) (O)
5 |
6 | let testbench () =
7 | let scope = Scope.create ~flatten_design:true () in
8 | let sim = Simulator.create (circuit_impl_exn scope) in
9 | let waves, sim = Waveform.create sim in
10 | let inputs = Cyclesim.inputs sim in
11 |
12 | let step ~sel_mem_for_reg_data ~alu_result ~data_output =
13 | inputs.sel_mem_for_reg_data := Bits.of_string sel_mem_for_reg_data;
14 | inputs.alu_result := Bits.of_string alu_result;
15 | inputs.data_output := Bits.of_string data_output;
16 | Cyclesim.cycle sim
17 | in
18 |
19 | step ~sel_mem_for_reg_data:"1'h0" ~alu_result:"32'h9" ~data_output:"32'h6";
20 |
21 | (* Output = alu_result *)
22 | step ~sel_mem_for_reg_data:"1'h1" ~alu_result:"32'h9" ~data_output:"32'h6";
23 |
24 | (* Output = data_output *)
25 | step ~sel_mem_for_reg_data:"1'h0" ~alu_result:"32'h9" ~data_output:"32'h6";
26 |
27 | (* Output = alu_result *)
28 | waves
29 |
30 | let%expect_test "writes back correct value depending on selector" =
31 | let waves = testbench () in
32 | Waveform.print ~wave_width:4 ~display_width:90 waves;
33 | [%expect
34 | {|
35 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐
36 | │ ││────────────────────────────── │
37 | │alu_result ││ 00000009 │
38 | │ ││────────────────────────────── │
39 | │ ││────────────────────────────── │
40 | │data_output ││ 00000006 │
41 | │ ││────────────────────────────── │
42 | │sel_mem_for_reg_da││ ┌─────────┐ │
43 | │ ││──────────┘ └───────── │
44 | │ ││──────────┬─────────┬───────── │
45 | │writeback_data ││ 00000009 │00000006 │00000009 │
46 | │ ││──────────┴─────────┴───────── │
47 | │ ││ │
48 | │ ││ │
49 | │ ││ │
50 | │ ││ │
51 | │ ││ │
52 | │ ││ │
53 | │ ││ │
54 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}]
55 |
--------------------------------------------------------------------------------
/test/instruction_decode/test_stall_unit.ml:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 | open Hardcaml_waveterm
3 | open Mips.Stall_unit
4 | module Simulator = Cyclesim.With_interface (I) (O)
5 |
6 | let gen_testbench () =
7 | let scope = Scope.create ~flatten_design:true () in
8 | let sim = Simulator.create (circuit_impl_exn scope) in
9 | let waves, sim = Waveform.create sim in
10 | let inputs = Cyclesim.inputs sim in
11 |
12 | let step ~rs ~rt ~e_dest ~e_sel_mem_for_reg_data =
13 | inputs.e_sel_mem_for_reg_data := Bits.of_string e_sel_mem_for_reg_data;
14 | inputs.rs := Bits.of_string rs;
15 | inputs.rt := Bits.of_string rt;
16 | inputs.e_dest := Bits.of_string e_dest;
17 |
18 | Cyclesim.cycle sim
19 | in
20 |
21 | (waves, step)
22 |
23 | let display_rules =
24 | [ Display_rule.port_name_is "stall_pc" ~wave_format:Wave_format.Bit ]
25 |
26 | let%expect_test "Stalls if LW in execute and should forward" =
27 | let waves, step = gen_testbench () in
28 | let step_lw = step ~e_sel_mem_for_reg_data:"1'b1" in
29 |
30 | step_lw ~rs:"5'h8" ~rt:"5'h8" ~e_dest:"5'h8";
31 | step_lw ~rs:"5'h7" ~rt:"5'h8" ~e_dest:"5'h8";
32 | step_lw ~rs:"5'h8" ~rt:"5'h7" ~e_dest:"5'h8";
33 |
34 | Waveform.print ~display_rules ~wave_width:4 ~display_width:90
35 | ~display_height:5 waves;
36 | [%expect
37 | {|
38 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐
39 | │stall_pc ││────────────────────────────── │
40 | │ ││ │
41 | │ ││ │
42 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}]
43 |
44 | let%expect_test "Doesn't stall if not LW in execute" =
45 | let waves, step = gen_testbench () in
46 |
47 | step ~e_sel_mem_for_reg_data:"1'b1" ~rs:"5'h7" ~rt:"5'h7" ~e_dest:"5'h8";
48 |
49 | Waveform.print ~display_rules ~wave_width:4 ~display_width:90
50 | ~display_height:5 waves;
51 | [%expect
52 | {|
53 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐
54 | │stall_pc ││ │
55 | │ ││────────── │
56 | │ ││ │
57 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}]
58 |
59 | let%expect_test "Doesn't stall if LW in execute, but shouldn't forward" =
60 | let waves, step = gen_testbench () in
61 |
62 | step ~e_sel_mem_for_reg_data:"1'b0" ~rs:"5'h8" ~rt:"5'h8" ~e_dest:"5'h7";
63 |
64 | Waveform.print ~display_rules ~wave_width:4 ~display_width:90
65 | ~display_height:5 waves;
66 | [%expect
67 | {|
68 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐
69 | │stall_pc ││ │
70 | │ ││────────── │
71 | │ ││ │
72 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}]
73 |
--------------------------------------------------------------------------------
/lib/cpu.ml:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 | open Hardcaml.Signal
3 | module UA = Hardcaml_arty.User_application
4 | module I = Hardcaml_arty.User_application.I
5 |
6 | module O = struct
7 | type 'a t = {
8 | uart_tx : 'a Hardcaml_arty.Uart.Byte_with_valid.t; [@rtlprefix "uart_tx_"]
9 | ethernet : 'a UA.Ethernet.O.t; [@rtlprefix "eth_"]
10 | writeback_data : 'a; [@bits 32]
11 | writeback_pc : 'a; [@bits 32]
12 | }
13 | [@@deriving sexp_of, hardcaml]
14 | end
15 |
16 | let uart_addr = "32'hFFFFFFFE"
17 | let delay_test_addr = "32'hFFFFFFFF"
18 |
19 | let circuit_impl program scope (input : t I.t) =
20 | let io_busy = wire 1 in
21 | let read_data = wire 32 in
22 | let datapath =
23 | Datapath.hierarchical program scope
24 | { Datapath.I.clock = input.clk_166; read_data; io_busy }
25 | in
26 |
27 | let using_uart_read = datapath.read_addr ==: of_string uart_addr in
28 | let using_uart_write = datapath.write_addr ==: of_string uart_addr in
29 | let uart =
30 | Uart.hierarchical scope
31 | {
32 | Uart.I.clock = input.clk_166;
33 | write_enable = using_uart_write &: datapath.write_enable;
34 | write_addr = datapath.write_addr;
35 | write_data = datapath.write_data;
36 | read_enable = using_uart_read &: datapath.read_enable;
37 | read_addr = datapath.read_addr;
38 | uart_rx = input.uart_rx;
39 | }
40 | in
41 | let uart_busy = using_uart_read |: using_uart_write &: uart.io_busy in
42 | let uart_read = Signal.sresize using_uart_read 32 &: uart.read_data in
43 |
44 | let using_delay_test_read =
45 | datapath.read_addr ==: of_string delay_test_addr
46 | in
47 | let using_delay_test_write =
48 | datapath.write_addr ==: of_string delay_test_addr
49 | in
50 | let delay_test_io =
51 | Delay_test_io.hierarchical scope
52 | {
53 | Delay_test_io.I.clock = input.clk_166;
54 | write_enable = using_delay_test_write &: datapath.write_enable;
55 | write_addr = datapath.write_addr;
56 | write_data = datapath.write_data;
57 | read_enable = using_delay_test_read &: datapath.read_enable;
58 | read_addr = datapath.read_addr;
59 | }
60 | in
61 | let delay_test_io_busy =
62 | using_delay_test_read |: using_delay_test_write &: delay_test_io.io_busy
63 | in
64 | let delay_test_read =
65 | Signal.sresize using_delay_test_read 32 &: delay_test_io.read_data
66 | in
67 |
68 | let using_memory_read = ~:using_delay_test_read &: ~:using_uart_read in
69 | let using_memory_write = ~:using_delay_test_write &: ~:using_uart_write in
70 | let memory =
71 | Memory.hierarchical scope
72 | {
73 | Memory.I.clock = input.clk_166;
74 | write_enable = using_memory_write &: datapath.write_enable;
75 | write_addr = datapath.write_addr;
76 | write_data = datapath.write_data;
77 | read_enable = using_memory_read &: datapath.read_enable;
78 | read_addr = datapath.read_addr;
79 | }
80 | in
81 | let memory_busy = using_memory_read |: using_memory_write &: memory.io_busy in
82 | let memory_read = Signal.sresize using_memory_read 32 &: memory.read_data in
83 |
84 | read_data <== (delay_test_read |: memory_read |: uart_read);
85 | io_busy <== (delay_test_io_busy |: memory_busy |: uart_busy);
86 |
87 | {
88 | O.ethernet = Hardcaml_arty.User_application.Ethernet.O.unused (module Signal);
89 | uart_tx = uart.uart_tx;
90 | writeback_data = datapath.writeback_data;
91 | writeback_pc = datapath.writeback_pc;
92 | }
93 |
--------------------------------------------------------------------------------
/arty/ips/design_1_clk_wiz_0_0/design_1_clk_wiz_0_0.veo:
--------------------------------------------------------------------------------
1 |
2 | //
3 | // (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved.
4 | //
5 | // This file contains confidential and proprietary information
6 | // of Xilinx, Inc. and is protected under U.S. and
7 | // international copyright and other intellectual property
8 | // laws.
9 | //
10 | // DISCLAIMER
11 | // This disclaimer is not a license and does not grant any
12 | // rights to the materials distributed herewith. Except as
13 | // otherwise provided in a valid license issued to you by
14 | // Xilinx, and to the maximum extent permitted by applicable
15 | // law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
16 | // WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
17 | // AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
18 | // BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
19 | // INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
20 | // (2) Xilinx shall not be liable (whether in contract or tort,
21 | // including negligence, or under any other theory of
22 | // liability) for any loss or damage of any kind or nature
23 | // related to, arising under or in connection with these
24 | // materials, including for any direct, or any indirect,
25 | // special, incidental, or consequential loss or damage
26 | // (including loss of data, profits, goodwill, or any type of
27 | // loss or damage suffered as a result of any action brought
28 | // by a third party) even if such damage or loss was
29 | // reasonably foreseeable or Xilinx had been advised of the
30 | // possibility of the same.
31 | //
32 | // CRITICAL APPLICATIONS
33 | // Xilinx products are not designed or intended to be fail-
34 | // safe, or for use in any application requiring fail-safe
35 | // performance, such as life-support or safety devices or
36 | // systems, Class III medical devices, nuclear facilities,
37 | // applications related to the deployment of airbags, or any
38 | // other applications that could lead to death, personal
39 | // injury, or severe property or environmental damage
40 | // (individually and collectively, "Critical
41 | // Applications"). Customer assumes the sole risk and
42 | // liability of any use of Xilinx products in Critical
43 | // Applications, subject only to applicable laws and
44 | // regulations governing limitations on product liability.
45 | //
46 | // THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
47 | // PART OF THIS FILE AT ALL TIMES.
48 | //
49 | //----------------------------------------------------------------------------
50 | // User entered comments
51 | //----------------------------------------------------------------------------
52 | // None
53 | //
54 | //----------------------------------------------------------------------------
55 | // Output Output Phase Duty Cycle Pk-to-Pk Phase
56 | // Clock Freq (MHz) (degrees) (%) Jitter (ps) Error (ps)
57 | //----------------------------------------------------------------------------
58 | // clk_out1__166.66667______0.000______50.0______118.758_____98.575
59 | // clk_out2__200.00000______0.000______50.0______114.829_____98.575
60 | // clk_out3__25.00000______0.000______50.0______175.402_____98.575
61 | //
62 | //----------------------------------------------------------------------------
63 | // Input Clock Freq (MHz) Input Jitter (UI)
64 | //----------------------------------------------------------------------------
65 | // __primary_________100.000____________0.010
66 |
67 | // The following must be inserted into your Verilog file for this
68 | // core to be instantiated. Change the instance name and port connections
69 | // (in parentheses) to your own signal names.
70 |
71 | //----------- Begin Cut here for INSTANTIATION Template ---// INST_TAG
72 |
73 | design_1_clk_wiz_0_0 instance_name
74 | (
75 | // Clock out ports
76 | .clk_out1(clk_out1), // output clk_out1
77 | .clk_out2(clk_out2), // output clk_out2
78 | .clk_out3(clk_out3), // output clk_out3
79 | // Status and control signals
80 | .resetn(resetn), // input resetn
81 | .locked(locked), // output locked
82 | // Clock in ports
83 | .clk_in1(clk_in1)); // input clk_in1
84 |
85 | // INST_TAG_END ------ End INSTANTIATION Template ---------
86 |
--------------------------------------------------------------------------------
/arty/ips/design_1_clk_wiz_0_0/design_1_clk_wiz_0_0.v:
--------------------------------------------------------------------------------
1 |
2 | // file: design_1_clk_wiz_0_0.v
3 | //
4 | // (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved.
5 | //
6 | // This file contains confidential and proprietary information
7 | // of Xilinx, Inc. and is protected under U.S. and
8 | // international copyright and other intellectual property
9 | // laws.
10 | //
11 | // DISCLAIMER
12 | // This disclaimer is not a license and does not grant any
13 | // rights to the materials distributed herewith. Except as
14 | // otherwise provided in a valid license issued to you by
15 | // Xilinx, and to the maximum extent permitted by applicable
16 | // law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
17 | // WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
18 | // AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
19 | // BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
20 | // INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
21 | // (2) Xilinx shall not be liable (whether in contract or tort,
22 | // including negligence, or under any other theory of
23 | // liability) for any loss or damage of any kind or nature
24 | // related to, arising under or in connection with these
25 | // materials, including for any direct, or any indirect,
26 | // special, incidental, or consequential loss or damage
27 | // (including loss of data, profits, goodwill, or any type of
28 | // loss or damage suffered as a result of any action brought
29 | // by a third party) even if such damage or loss was
30 | // reasonably foreseeable or Xilinx had been advised of the
31 | // possibility of the same.
32 | //
33 | // CRITICAL APPLICATIONS
34 | // Xilinx products are not designed or intended to be fail-
35 | // safe, or for use in any application requiring fail-safe
36 | // performance, such as life-support or safety devices or
37 | // systems, Class III medical devices, nuclear facilities,
38 | // applications related to the deployment of airbags, or any
39 | // other applications that could lead to death, personal
40 | // injury, or severe property or environmental damage
41 | // (individually and collectively, "Critical
42 | // Applications"). Customer assumes the sole risk and
43 | // liability of any use of Xilinx products in Critical
44 | // Applications, subject only to applicable laws and
45 | // regulations governing limitations on product liability.
46 | //
47 | // THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
48 | // PART OF THIS FILE AT ALL TIMES.
49 | //
50 | //----------------------------------------------------------------------------
51 | // User entered comments
52 | //----------------------------------------------------------------------------
53 | // None
54 | //
55 | //----------------------------------------------------------------------------
56 | // Output Output Phase Duty Cycle Pk-to-Pk Phase
57 | // Clock Freq (MHz) (degrees) (%) Jitter (ps) Error (ps)
58 | //----------------------------------------------------------------------------
59 | // clk_out1__166.66667______0.000______50.0______118.758_____98.575
60 | // clk_out2__200.00000______0.000______50.0______114.829_____98.575
61 | // clk_out3__25.00000______0.000______50.0______175.402_____98.575
62 | //
63 | //----------------------------------------------------------------------------
64 | // Input Clock Freq (MHz) Input Jitter (UI)
65 | //----------------------------------------------------------------------------
66 | // __primary_________100.000____________0.010
67 |
68 | `timescale 1ps/1ps
69 |
70 | (* CORE_GENERATION_INFO = "design_1_clk_wiz_0_0,clk_wiz_v6_0_9_0_0,{component_name=design_1_clk_wiz_0_0,use_phase_alignment=true,use_min_o_jitter=false,use_max_i_jitter=false,use_dyn_phase_shift=false,use_inclk_switchover=false,use_dyn_reconfig=false,enable_axi=0,feedback_source=FDBK_AUTO,PRIMITIVE=MMCM,num_out_clk=3,clkin1_period=10.000,clkin2_period=10.000,use_power_down=false,use_reset=true,use_locked=true,use_inclk_stopped=false,feedback_type=SINGLE,CLOCK_MGR_TYPE=NA,manual_override=false}" *)
71 |
72 | module design_1_clk_wiz_0_0
73 | (
74 | // Clock out ports
75 | output clk_out1,
76 | output clk_out2,
77 | output clk_out3,
78 | // Status and control signals
79 | input resetn,
80 | output locked,
81 | // Clock in ports
82 | input clk_in1
83 | );
84 |
85 | design_1_clk_wiz_0_0_clk_wiz inst
86 | (
87 | // Clock out ports
88 | .clk_out1(clk_out1),
89 | .clk_out2(clk_out2),
90 | .clk_out3(clk_out3),
91 | // Status and control signals
92 | .resetn(resetn),
93 | .locked(locked),
94 | // Clock in ports
95 | .clk_in1(clk_in1)
96 | );
97 |
98 | endmodule
99 |
--------------------------------------------------------------------------------
/lib/instruction_decode/instruction_decode.ml:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 | open Hardcaml.Signal
3 |
4 | module I = struct
5 | type 'a t = {
6 | clock : 'a; [@bits 1]
7 | enable_pipeline : 'a; [@bits 1]
8 | writeback_reg_write_enable : 'a; [@bits 1]
9 | writeback_address : 'a; [@bits 5]
10 | writeback_data : 'a; [@bits 32]
11 | instruction : 'a; [@bits 32]
12 | e_alu_output : 'a; [@bits 32]
13 | m_alu_output : 'a; [@bits 32]
14 | m_data_output : 'a; [@bits 32]
15 | }
16 | [@@deriving sexp_of, hardcaml]
17 | end
18 |
19 | module O = struct
20 | type 'a t = {
21 | control_signals : 'a Control_unit.Control_signals.t;
22 | alu_a : 'a; [@bits 32]
23 | alu_b : 'a; [@bits 32]
24 | rdest : 'a; [@bits 5]
25 | se_imm : 'a; [@bits 32]
26 | alu_imm : 'a; [@bits 32]
27 | addr : 'a; [@bits 26]
28 | }
29 | [@@deriving sexp_of, hardcaml]
30 | end
31 |
32 | let regfile rs rt clock write_enable write_address write_data =
33 | let write_port =
34 | { write_clock = clock; write_address; write_enable; write_data }
35 | in
36 | let number_of_regs = 32 in
37 | let regs =
38 | multiport_memory number_of_regs ~write_ports:[| write_port |]
39 | ~read_addresses:[| rs; rt |]
40 | in
41 | let alu_a =
42 | mux2 (write_enable &: (write_address ==: rs)) write_data regs.(0)
43 | in
44 | let alu_b =
45 | mux2 (write_enable &: (write_address ==: rt)) write_data regs.(1)
46 | in
47 |
48 | (alu_a, alu_b)
49 |
50 | let stall_signals scope (sigs : _ Control_unit.Control_signals.t) rs rt e_dest
51 | e_sel_mem_for_reg_data =
52 | let stall_unit =
53 | Stall_unit.hierarchical scope { rs; rt; e_dest; e_sel_mem_for_reg_data }
54 | in
55 | let stall_pc = stall_unit.stall_pc in
56 | {
57 | sigs with
58 | stall_pc;
59 | reg_write_enable = mux2 stall_pc gnd sigs.reg_write_enable;
60 | mem_write_enable = mux2 stall_pc gnd sigs.mem_write_enable;
61 | }
62 |
63 | let circuit_impl (scope : Scope.t) (input : _ I.t) =
64 | let enable = input.enable_pipeline in
65 |
66 | let control_unit =
67 | Control_unit.hierarchical scope { instruction = input.instruction }
68 | in
69 |
70 | let parsed = control_unit.parsed_instruction in
71 | let rs_val, rt_val =
72 | regfile parsed.rs parsed.rt input.clock input.writeback_reg_write_enable
73 | input.writeback_address input.writeback_data
74 | in
75 |
76 | let r = Reg_spec.create ~clock:input.clock () in
77 | let e_dest = reg ~enable r parsed.rdest in
78 | let m_dest = pipeline ~n:2 ~enable r parsed.rdest in
79 |
80 | let m2reg = control_unit.control_signals.sel_mem_for_reg_data in
81 | let wreg = control_unit.control_signals.reg_write_enable in
82 | let e_sel_mem_for_reg_data = reg ~enable r m2reg in
83 | let m_sel_mem_for_reg_data = pipeline ~n:2 ~enable r m2reg in
84 | let e_reg_write_enable = reg ~enable r wreg in
85 | let m_reg_write_enable = pipeline ~n:2 ~enable r wreg in
86 |
87 | let full_control_signals =
88 | stall_signals scope control_unit.control_signals parsed.rs parsed.rt e_dest
89 | e_sel_mem_for_reg_data
90 | in
91 |
92 | let e_stalled = reg ~enable r full_control_signals.stall_pc in
93 |
94 | let forwarding_unit_inputs reg reg_value =
95 | {
96 | Forwarding_unit.I.options =
97 | {
98 | Forwarding_unit.Data_options.reg_value;
99 | e_alu_output = input.e_alu_output;
100 | m_alu_output = input.m_alu_output;
101 | m_data_output = input.m_data_output;
102 | };
103 | controls =
104 | {
105 | Forwarding_unit.Controls.e_sel_mem_for_reg_data;
106 | m_sel_mem_for_reg_data;
107 | e_reg_write_enable;
108 | m_reg_write_enable;
109 | e_stalled;
110 | };
111 | source = reg;
112 | e_dest;
113 | m_dest;
114 | }
115 | in
116 |
117 | let fwd_a =
118 | Forwarding_unit.hierarchical scope (forwarding_unit_inputs parsed.rs rs_val)
119 | in
120 | let fwd_b =
121 | Forwarding_unit.hierarchical scope (forwarding_unit_inputs parsed.rt rt_val)
122 | in
123 |
124 | let check_zero_reg reg fwd =
125 | mux2 (reg ==: of_string "5'b0") (of_string "32'b0") fwd
126 | in
127 |
128 | let alu_a = check_zero_reg parsed.rs fwd_a.forward_data in
129 | let alu_b = check_zero_reg parsed.rt fwd_b.forward_data in
130 |
131 | {
132 | O.control_signals = full_control_signals;
133 | alu_a;
134 | alu_b;
135 | rdest = parsed.rdest;
136 | se_imm = parsed.se_imm;
137 | alu_imm = parsed.alu_imm;
138 | addr = parsed.addr;
139 | }
140 |
141 | let circuit_impl_exn scope input =
142 | let module W = Width_check.With_interface (I) (O) in
143 | W.check_widths (circuit_impl scope) input
144 |
145 | let hierarchical scope input =
146 | let module H = Hierarchy.In_scope (I) (O) in
147 | H.hierarchical ~scope ~name:"instruction_decode" circuit_impl_exn input
148 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## [1.0.0](https://github.com/askvortsov1/hardcaml-mips/compare/v0.14.0...v1.0.0)
4 |
5 | - Implemented control flow instructions
6 | - j, jal, jr
7 | - bne, beq
8 | - Fixed sw source bugs
9 | - Use alu_b instead of alu_a
10 | - Pipeline data address properly
11 | - Use zero-extended immediate for shift instructions
12 | - Added integration tests
13 | - Added an actual program
14 | - Bump ocamlformat version
15 |
16 | ## [0.14.0](https://github.com/askvortsov1/hardcaml-mips/compare/v0.13.0...v0.14.0)
17 |
18 | - Added stalls
19 | - We stall if there's a LW in Execute, and we need to forward Execute => Decode
20 | - This is needed because LW data isn't available for forwarding until the Memory stage
21 | - Also moved "next PC" logic out of "instruction fetch": this will be its own module in a coming release.
22 |
23 | ## [0.13.0](https://github.com/askvortsov1/hardcaml-mips/compare/v0.12.1...v0.13.0)
24 |
25 | Refactor to avoid writeback => decode forwarding
26 |
27 | - Instead, support write-before-read in the regfile
28 | - Also, fix a wiring issue with forwarding
29 |
30 | ## [0.12.1](https://github.com/askvortsov1/hardcaml-mips/compare/v0.11.1...v0.12.1)
31 |
32 | - Use interactive waveform viewer
33 |
34 | ## [0.11.1](https://github.com/askvortsov1/hardcaml-mips/compare/v0.10.0...v0.11.1)
35 |
36 | - Added a forwarding unit
37 | - Forwards values from execute, memory, and writeback
38 | - `rs_val` and `rt_val` renamed to `alu_a` and `alu_b` throughout the design.
39 | - The register file no longer delays writes by half a cycle
40 | - Simulating half-cycle operations is [not supported in Hardcaml](https://github.com/janestreet/hardcaml/issues/11).
41 |
42 | ## [0.10.0](https://github.com/askvortsov1/hardcaml-mips/compare/v0.9.0...v0.10.0)
43 |
44 | - Outputs verilog code to a separate file, "mips_datapath.v"
45 |
46 | ## [0.9.0](https://github.com/askvortsov1/hardcaml-mips/compare/v0.8.0...v0.9.0)
47 |
48 | - Added most MIPS instructions
49 | - Excluded mult/divide because we don't have hi/lo registers yet
50 | - Excluded jump, branch because we don't have next_pc selector logic yet
51 | - Excluded system calls / exception handling because we don't have an exception handling unit.
52 | - Output `pc` in datapath
53 | - Added some regfile-initializing instructions in the sample program
54 | - Split `imm` parsed instructions into `ze_imm` (for eventual branching) and `alu_imm` (for ALU ops, is zero or sign extended depending on the instruction)
55 |
56 | ## [0.8.0](https://github.com/askvortsov1/hardcaml-mips/compare/v0.7.0...v0.8.0)
57 |
58 | - Added memory and writeback stages. This completes the basic core of our CPU.
59 | - Added write support to regfile, made it write-before-read to reduce hazards.
60 |
61 | ## [0.7.0](https://github.com/askvortsov1/hardcaml-mips/compare/v0.6.1...v0.7.0)
62 |
63 | - Added instruction decode stage
64 | - Includes a 3 part control unit from v0.6.1
65 | - Created register file
66 | - Added instruction execute stage
67 | - Created ALU with support for adds and subtracts
68 | - Added tests for new components
69 |
70 | ## [0.6.1](https://github.com/askvortsov1/hardcaml-mips/compare/v0.5.2...v0.6.1)
71 |
72 | - Added control unit.
73 | - Split into [3 components](https://excalidraw.com/#json=4874675947569152,f4jus3Ehk-DGZspiJAGUWw) for maintainability.
74 |
75 | ## [0.5.2](https://github.com/askvortsov1/hardcaml-mips/compare/v0.4.0...v0.5.2)
76 |
77 | - Renamed circuit `create` functions to `circuit_impl`.
78 | - Created a `Width_check.With_interface` functor with a `check_widths` function that checks input/output width compliance for circuit implementation.
79 | - Instruction memory now returns noops when `pc` exceeds the length of the program to avoid unexpected effects.
80 | - Standardized and cleaned up naming input
81 | - Inputs are type hinted in the circuit implementation functions, and derived functions use type inference for concision.
82 |
83 | ## [0.4.0](https://github.com/askvortsov1/hardcaml-mips/compare/v0.3.0...v0.4.0)
84 |
85 | - Implemented feedback in datapath via register. This allows us to store and mutate the state of our system over time.
86 |
87 | ## [0.3.0](https://github.com/askvortsov1/hardcaml-mips/compare/v0.2.0...v0.3.0)
88 |
89 | - Implemented `instruction_memory`. The program being executed is treated as an input to the entire processor.
90 | - See `instruction_fetch.ml` for an explanation of why we implemented instruction memory the way we did.
91 | - Defined `Program` module to abstract away the concept of a program.
92 |
93 | ## [0.2.1](https://github.com/askvortsov1/hardcaml-mips/compare/v0.1.2...v0.2.0)
94 |
95 | Proof of concept for module hierarchies:
96 |
97 | - Started instruction fetch module
98 | - No memory or registers yet, just constant output for now
99 |
100 | ## [0.1.2](https://github.com/askvortsov1/hardcaml-mips/tree/v0.1.2) 6/14/2021
101 |
102 | Proof of concept:
103 |
104 | - Created trivial circuit
105 | - Added waveform-based expect test
106 | - Built executable to print circuit in Verilog
--------------------------------------------------------------------------------
/test/instruction_execute/test_alu.ml:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 | open Hardcaml_waveterm
3 | open Mips.Alu
4 | module Simulator = Cyclesim.With_interface (I) (O)
5 |
6 | let testbench () =
7 | let scope = Scope.create ~flatten_design:true () in
8 | let sim = Simulator.create (circuit_impl_exn scope) in
9 | let waves, sim = Waveform.create sim in
10 | let inputs = Cyclesim.inputs sim in
11 |
12 | let step ~arg_a ~arg_b ~alu_control =
13 | inputs.arg_a := Bits.of_string arg_a;
14 | inputs.arg_b := Bits.of_string arg_b;
15 | inputs.alu_control := Bits.of_constant (Signal.to_constant alu_control);
16 | Cyclesim.cycle sim
17 | in
18 |
19 | step ~arg_a:"32'h5" ~arg_b:"32'h10" ~alu_control:Mips.Control_unit.Alu_ops.add;
20 | step ~arg_a:"32'h10" ~arg_b:"32'h5" ~alu_control:Mips.Control_unit.Alu_ops.addu;
21 | step ~arg_a:"32'h000F0FF0" ~arg_b:"32'hFF0F00FF" ~alu_control:Mips.Control_unit.Alu_ops.and_;
22 | step ~arg_a:"32'hABCDEF01" ~arg_b:"32'h9876ABCD" ~alu_control:Mips.Control_unit.Alu_ops.lui;
23 | step ~arg_a:"32'h000F0FF0" ~arg_b:"32'hFF0F00FF" ~alu_control:Mips.Control_unit.Alu_ops.or_;
24 | step ~arg_a:"32'h0" ~arg_b:"32'hFFFFFFFF" ~alu_control:Mips.Control_unit.Alu_ops.slt;
25 | step ~arg_a:"32'h0" ~arg_b:"32'hFFFFFFFF" ~alu_control:Mips.Control_unit.Alu_ops.sltu;
26 | step ~arg_a:"32'h2" ~arg_b:"32'h8000000F0" ~alu_control:Mips.Control_unit.Alu_ops.sll;
27 | step ~arg_a:"32'h2" ~arg_b:"32'h8000000F0" ~alu_control:Mips.Control_unit.Alu_ops.sra;
28 | step ~arg_a:"32'h2" ~arg_b:"32'h8000000F0" ~alu_control:Mips.Control_unit.Alu_ops.srl;
29 | step ~arg_a:"32'h15" ~arg_b:"32'h2" ~alu_control:Mips.Control_unit.Alu_ops.sub;
30 | step ~arg_a:"32'h15" ~arg_b:"32'h2" ~alu_control:Mips.Control_unit.Alu_ops.subu;
31 | step ~arg_a:"32'h005F" ~arg_b:"32'hF0AF" ~alu_control:Mips.Control_unit.Alu_ops.xor;
32 |
33 | waves
34 |
35 | let%expect_test "Operations behave as expected"
36 | =
37 | let waves = testbench () in
38 | Waveform.print ~wave_width:4 ~display_width:155 waves;
39 | [%expect
40 | {|
41 | ┌Signals───────────┐┌Waves────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
42 | │ ││──────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬───────── │
43 | │alu_control ││ 02 │03 │04 │05 │06 │07 │08 │09 │0A │0B │0C │0D │0E │
44 | │ ││──────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴───────── │
45 | │ ││──────────┬─────────┬─────────┬─────────┬─────────┬───────────────────┬─────────────────────────────┬───────────────────┬───────── │
46 | │arg_a ││ 00000005 │00000010 │000F0FF0 │ABCDEF01 │000F0FF0 │00000000 │00000002 │00000015 │0000005F │
47 | │ ││──────────┴─────────┴─────────┴─────────┴─────────┴───────────────────┴─────────────────────────────┴───────────────────┴───────── │
48 | │ ││──────────┬─────────┬─────────┬─────────┬─────────┬───────────────────┬─────────────────────────────┬───────────────────┬───────── │
49 | │arg_b ││ 00000010 │00000005 │FF0F00FF │9876ABCD │FF0F00FF │FFFFFFFF │000000F0 │00000002 │0000F0AF │
50 | │ ││──────────┴─────────┴─────────┴─────────┴─────────┴───────────────────┴─────────────────────────────┴───────────────────┴───────── │
51 | │ ││────────────────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬───────────────────┬───────────────────┬───────── │
52 | │result ││ 00000015 │000F00F0 │ABCD0000 │FF0F0FFF │00000001 │00000000 │000003C0 │0000003C │00000013 │0000F0F0 │
53 | │ ││────────────────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴───────────────────┴───────────────────┴───────── │
54 | │ ││ │
55 | │ ││ │
56 | │ ││ │
57 | │ ││ │
58 | │ ││ │
59 | │ ││ │
60 | └──────────────────┘└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
61 | |}]
62 |
--------------------------------------------------------------------------------
/test/io/test_memory.ml:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 | open Hardcaml_waveterm
3 | open Mips.Memory
4 | module Simulator = Cyclesim.With_interface (I) (O)
5 |
6 | type test_input = {
7 | write_enable : string;
8 | write_data : string;
9 | data_address : string;
10 | }
11 |
12 | let testbench () =
13 | let scope = Scope.create ~flatten_design:true () in
14 | let sim = Simulator.create (circuit_impl scope) in
15 | let waves, sim = Waveform.create sim in
16 | let inputs = Cyclesim.inputs sim in
17 |
18 | let step ~test =
19 | inputs.write_enable := Bits.of_string test.write_enable;
20 | inputs.read_addr := Bits.of_string test.data_address;
21 | inputs.write_addr := Bits.of_string test.data_address;
22 | inputs.write_data := Bits.of_string test.write_data;
23 | Cyclesim.cycle sim
24 | in
25 |
26 | step
27 | ~test:
28 | { write_enable = "1'h0"; data_address = "32'h9"; write_data = "32'h7" };
29 | (* alu_a should now be 8 after this step *)
30 | step
31 | ~test:
32 | { write_enable = "1'h0"; data_address = "32'h9"; write_data = "32'h6" };
33 |
34 | (* Memory should be 0 since everything has been disabled so far *)
35 | step
36 | ~test:
37 | { write_enable = "1'h1"; data_address = "32'h9"; write_data = "32'h86" };
38 |
39 | step
40 | ~test:
41 | { write_enable = "1'h0"; data_address = "32'h9"; write_data = "32'h6" };
42 | (* Now we can read what we wrote.
43 | * It's delayed by a stage since the simulator isn't half-cycle accurate
44 | * (see test_instruction_decode for more details) but we don't care about
45 | * that for data memory.
46 | *)
47 | waves
48 |
49 | let%expect_test "can we read and write to/from data memory properly" =
50 | let waves = testbench () in
51 | Waveform.print ~wave_width:4 ~display_width:90 ~display_height:35 waves;
52 | [%expect
53 | {|
54 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐
55 | │clock ││┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
56 | │ ││ └────┘ └────┘ └────┘ └────┘ └────┘ └────┘ └──│
57 | │ ││──────────────────────────────────────── │
58 | │read_addr ││ 00000009 │
59 | │ ││──────────────────────────────────────── │
60 | │ ││──────────────────────────────────────── │
61 | │write_addr ││ 00000009 │
62 | │ ││──────────────────────────────────────── │
63 | │ ││──────────┬─────────┬─────────┬───────── │
64 | │write_data ││ 00000007 │00000006 │00000086 │00000006 │
65 | │ ││──────────┴─────────┴─────────┴───────── │
66 | │write_enable ││ ┌─────────┐ │
67 | │ ││────────────────────┘ └───────── │
68 | │io_busy ││ │
69 | │ ││──────────────────────────────────────── │
70 | │ ││──────────────────────────────┬───────── │
71 | │read_data ││ 00000000 │00000086 │
72 | │ ││──────────────────────────────┴───────── │
73 | │ ││ │
74 | │ ││ │
75 | │ ││ │
76 | │ ││ │
77 | │ ││ │
78 | │ ││ │
79 | │ ││ │
80 | │ ││ │
81 | │ ││ │
82 | │ ││ │
83 | │ ││ │
84 | │ ││ │
85 | │ ││ │
86 | │ ││ │
87 | │ ││ │
88 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}]
89 |
--------------------------------------------------------------------------------
/lib/datapath.ml:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 | open Hardcaml.Signal
3 |
4 | module I = struct
5 | type 'a t = {
6 | clock : 'a; [@bits 1]
7 | io_busy : 'a; [@bits 1]
8 | read_data : 'a; [@bits 32]
9 | }
10 | [@@deriving sexp_of, hardcaml]
11 | end
12 |
13 | module O = struct
14 | type 'a t = {
15 | write_enable : 'a; [@bits 1]
16 | write_addr : 'a; [@bits 32]
17 | write_data : 'a; [@bits 32]
18 | read_enable : 'a; [@bits 1]
19 | read_addr : 'a; [@bits 32]
20 | writeback_data : 'a; [@bits 32]
21 | writeback_pc : 'a; [@bits 32]
22 | }
23 | [@@deriving sexp_of, hardcaml]
24 | end
25 |
26 | let circuit_impl (program : Program.t) (scope : Scope.t) (input : _ I.t) =
27 | (* Stall the pipeline while devices on the bus are busy. *)
28 | let enable = ~:(input.io_busy) in
29 | let r = Reg_spec.create ~clock:input.clock () in
30 |
31 | (* Instruction Fetch Stage *)
32 | let pc = wire 32 in
33 |
34 | let instruction_fetch = Instruction_fetch.hierarchical program scope { pc } in
35 |
36 | (* Instruction Decode *)
37 | let reg_write_enable = wire 1 in
38 | let reg_write_enable_reg = pipeline ~n:3 ~enable r reg_write_enable in
39 | let writeback_address = wire 5 in
40 | let writeback_address_reg = pipeline ~n:3 ~enable r writeback_address in
41 | let writeback_data = wire 32 in
42 |
43 | let prev_stall_pc = wire 1 in
44 | let prev_instruction =
45 | pipeline ~n:2 ~enable r instruction_fetch.instruction
46 | in
47 | let curr_instruction = reg ~enable r instruction_fetch.instruction in
48 | let instruction = mux2 prev_stall_pc prev_instruction curr_instruction in
49 |
50 | let e_alu_output = wire 32 in
51 | let m_alu_output = wire 32 in
52 | let instruction_decode =
53 | Instruction_decode.hierarchical scope
54 | {
55 | Instruction_decode.I.clock = input.clock;
56 | enable_pipeline = enable;
57 | writeback_reg_write_enable = reg_write_enable_reg;
58 | writeback_address = writeback_address_reg;
59 | writeback_data;
60 | instruction;
61 | e_alu_output;
62 | m_alu_output;
63 | m_data_output = input.read_data;
64 | }
65 | in
66 | let ctrl_sigs = instruction_decode.control_signals in
67 | reg_write_enable <== ctrl_sigs.reg_write_enable;
68 | writeback_address <== instruction_decode.rdest;
69 |
70 | let gen_next_pc =
71 | Gen_next_pc.hierarchical scope
72 | {
73 | Gen_next_pc.I.alu_a = instruction_decode.alu_a;
74 | alu_b = instruction_decode.alu_b;
75 | addr = instruction_decode.addr;
76 | se_imm = instruction_decode.se_imm;
77 | pc;
78 | prev_pc = reg ~enable r pc;
79 | pc_sel = ctrl_sigs.pc_sel;
80 | }
81 | in
82 |
83 | let pc_reg =
84 | reg ~enable r (mux2 ctrl_sigs.stall_pc pc gen_next_pc.next_pc)
85 | in
86 | pc <== pc_reg;
87 | prev_stall_pc <== reg ~enable r ctrl_sigs.stall_pc;
88 |
89 | (* Instruction Execute *)
90 | let sel_shift_for_alu = reg ~enable r ctrl_sigs.sel_shift_for_alu in
91 | let sel_imm_for_alu = reg ~enable r ctrl_sigs.sel_imm_for_alu in
92 | let alu_control = reg ~enable r ctrl_sigs.alu_control in
93 | let alu_a = reg ~enable r instruction_decode.alu_a in
94 | let alu_b = reg ~enable r instruction_decode.alu_b in
95 | let alu_imm = reg ~enable r instruction_decode.alu_imm in
96 | let jal = reg ~enable r ctrl_sigs.jal in
97 | let instruction_execute =
98 | Instruction_execute.hierarchical scope
99 | {
100 | alu_a;
101 | alu_b;
102 | imm = alu_imm;
103 | sel_shift_for_alu;
104 | sel_imm_for_alu;
105 | alu_control;
106 | jal;
107 | prev2_pc = pipeline ~n:2 ~enable r pc;
108 | }
109 | in
110 | e_alu_output <== instruction_execute.alu_result;
111 | m_alu_output <== reg ~enable r instruction_execute.alu_result;
112 |
113 | (* Memory *)
114 | let mem_write_enable =
115 | pipeline ~n:2 ~enable r ctrl_sigs.mem_write_enable
116 | in
117 | let mem_read_enable =
118 | pipeline ~n:2 ~enable r ctrl_sigs.mem_read_enable
119 | in
120 | let data = pipeline ~n:2 ~enable r instruction_decode.alu_b in
121 | let data_address = reg ~enable r instruction_execute.alu_result in
122 |
123 | (* Memory access is handled by the bus. *)
124 |
125 | (* Writeback *)
126 | let sel_mem_for_reg_data =
127 | pipeline ~n:3 ~enable r ctrl_sigs.sel_mem_for_reg_data
128 | in
129 | let alu_result = pipeline ~n:2 ~enable r instruction_execute.alu_result in
130 | let data_output = reg ~enable r input.read_data in
131 |
132 | let writeback =
133 | Writeback.hierarchical scope
134 | { Writeback.I.sel_mem_for_reg_data; alu_result; data_output }
135 | in
136 | writeback_data <== writeback.writeback_data;
137 |
138 | (* Outputs *)
139 | {
140 | O.write_enable = mem_write_enable;
141 | write_addr = data_address;
142 | write_data = data;
143 | read_enable = mem_read_enable;
144 | read_addr = data_address;
145 | writeback_data;
146 | writeback_pc = pipeline ~n:4 ~enable r pc;
147 | }
148 |
149 | let circuit_impl_exn program scope input =
150 | let module W = Width_check.With_interface (I) (O) in
151 | W.check_widths (circuit_impl program scope) input
152 |
153 | let hierarchical program scope input =
154 | let module H = Hierarchy.In_scope (I) (O) in
155 | H.hierarchical ~scope ~name:"datapath" (circuit_impl_exn program) input
156 |
--------------------------------------------------------------------------------
/test/instruction_decode/test_forwarding_unit.ml:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 | open Hardcaml_waveterm
3 | open Mips.Forwarding_unit
4 | module Simulator = Cyclesim.With_interface (I) (O)
5 |
6 | let gen_testbench () =
7 | let scope = Scope.create ~flatten_design:true () in
8 | let sim = Simulator.create (circuit_impl_exn scope) in
9 | let waves, sim = Waveform.create sim in
10 | let inputs = Cyclesim.inputs sim in
11 |
12 | let step ?(e_dest = "5'h9") ?(m_dest = "5'h9") ?(e_mem2reg = "1'b0")
13 | ?(m_mem2reg = "1'b0") ?(e_rwrite = "1'b1") ?(m_rwrite = "1'b1")
14 | ?(e_stalled = "1'b0") () =
15 | inputs.options.reg_value := Bits.of_string "32'd0";
16 | inputs.options.e_alu_output := Bits.of_string "32'd1";
17 | inputs.options.m_alu_output := Bits.of_string "32'd2";
18 | inputs.options.m_data_output := Bits.of_string "32'd3";
19 | inputs.source := Bits.of_string "5'd8";
20 | inputs.e_dest := Bits.of_string e_dest;
21 | inputs.m_dest := Bits.of_string m_dest;
22 | inputs.controls.e_sel_mem_for_reg_data := Bits.of_string e_mem2reg;
23 | inputs.controls.m_sel_mem_for_reg_data := Bits.of_string m_mem2reg;
24 | inputs.controls.e_reg_write_enable := Bits.of_string e_rwrite;
25 | inputs.controls.m_reg_write_enable := Bits.of_string m_rwrite;
26 | inputs.controls.e_stalled := Bits.of_string e_stalled;
27 | Cyclesim.cycle sim
28 | in
29 | (waves, step)
30 |
31 | let display_rules =
32 | [ Display_rule.port_name_is "forward_data" ~wave_format:Wave_format.Hex ]
33 |
34 | let%expect_test "Forwards correctly, if should forward" =
35 | let waves, step = gen_testbench () in
36 |
37 | step ~e_dest:"5'h8" ();
38 | step ~m_dest:"5'h8" ~m_mem2reg:"1'b0" ();
39 | step ~m_dest:"5'h8" ~m_mem2reg:"1'b1" ();
40 |
41 | Waveform.print ~display_rules ~wave_width:4 ~display_width:90
42 | ~display_height:5 waves;
43 | [%expect
44 | {|
45 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐
46 | │ ││──────────┬─────────┬───────── │
47 | │forward_data ││ 00000001 │00000002 │00000003 │
48 | │ ││──────────┴─────────┴───────── │
49 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}]
50 |
51 | let%expect_test "Doesn't forward for instructions that don't write to registers"
52 | =
53 | let waves, step = gen_testbench () in
54 |
55 | step ~e_dest:"5'h8" ~e_rwrite:"1'b0" ();
56 | step ~m_dest:"5'h8" ~m_mem2reg:"1'b0" ~m_rwrite:"1'b0" ();
57 | step ~m_dest:"5'h8" ~m_mem2reg:"1'b1" ~m_rwrite:"1'b0" ();
58 |
59 | Waveform.print ~display_rules ~wave_width:4 ~display_width:90
60 | ~display_height:5 waves;
61 | [%expect
62 | {|
63 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐
64 | │ ││────────────────────────────── │
65 | │forward_data ││ 00000000 │
66 | │ ││────────────────────────────── │
67 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}]
68 |
69 | let%expect_test "Prioritizes which stage forwarding happens if dest is same" =
70 | let waves, step = gen_testbench () in
71 |
72 | step ~e_dest:"5'h8" ~m_dest:"5'h8" ~m_mem2reg:"1'b0" ();
73 | step ~e_dest:"5'h8" ~m_dest:"5'h8" ~m_mem2reg:"1'b1" ();
74 |
75 | Waveform.print ~display_rules ~wave_width:4 ~display_width:90
76 | ~display_height:5 waves;
77 | [%expect
78 | {|
79 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐
80 | │ ││──────────────────── │
81 | │forward_data ││ 00000001 │
82 | │ ││──────────────────── │
83 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}]
84 |
85 | let%expect_test "Ensures no forwarding occurs when LW is in execute stage" =
86 | let waves, step = gen_testbench () in
87 |
88 | step ~e_dest:"5'h8" ~e_mem2reg:"1'b1" ();
89 |
90 | Waveform.print ~display_rules ~wave_width:4 ~display_width:90
91 | ~display_height:5 waves;
92 | [%expect
93 | {|
94 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐
95 | │ ││────────── │
96 | │forward_data ││ 00000000 │
97 | │ ││────────── │
98 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}]
99 |
100 | let%expect_test "Does not forward from previous if prev was stalled." =
101 | let waves, step = gen_testbench () in
102 |
103 | step ~e_dest:"5'h8" ~m_dest:"5'h8" ~m_mem2reg:"1'b1" ~e_stalled:"1'b0" ();
104 | step ~e_dest:"5'h8" ~m_dest:"5'h8" ~m_mem2reg:"1'b1" ~e_stalled:"1'b1" ();
105 |
106 | Waveform.print ~display_rules ~wave_width:4 ~display_width:90
107 | ~display_height:5 waves;
108 | [%expect
109 | {|
110 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐
111 | │ ││──────────┬───────── │
112 | │forward_data ││ 00000001 │00000003 │
113 | │ ││──────────┴───────── │
114 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}]
--------------------------------------------------------------------------------
/lib/io/uart.ml:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 | open Hardcaml.Signal
3 |
4 | module Word_with_valid = struct
5 | module Pre = struct
6 | include With_valid
7 |
8 | let t = { valid = ("valid", 1); value = ("value", 32) }
9 | end
10 |
11 | include Pre
12 | include Hardcaml.Interface.Make (Pre)
13 | end
14 |
15 | let num_start_bits = 1
16 | let num_data_bits = 8
17 | let num_stop_bits = 1
18 | let bits_per_packet = num_start_bits + num_data_bits + num_stop_bits
19 |
20 | let cycles_per_bit =
21 | 166_667_000 / 115_200 (* 166.667 MHz running at 115200 baud *)
22 |
23 | let cycles_per_packet = bits_per_packet * cycles_per_bit
24 | let newline_hex = 0x0A
25 |
26 | module Rx_buffer = struct
27 | module States = struct
28 | type t = S_idle | S_wait_next_byte | S_finished
29 | [@@deriving sexp_of, compare, enumerate]
30 | end
31 |
32 | let create ~clock ~read_enable
33 | (input : t Hardcaml_arty.Uart.Byte_with_valid.t) =
34 | let spec = Reg_spec.create ~clock () in
35 |
36 | let sm = Always.State_machine.create (module States) spec ~enable:vdd in
37 |
38 | (* This will never be true when sm.is S_finished,
39 | * b/c input.valid is only vdd for one cycle/packet
40 | *)
41 | let should_update_buffer =
42 | input.valid &: (sm.is S_wait_next_byte |: read_enable)
43 | in
44 | let buffer_index = Always.Variable.reg spec ~enable:vdd ~width:2 in
45 | let reg_read_buffer =
46 | reg_fb spec ~enable:vdd ~width:32 ~f:(fun curr ->
47 | let curr_byte_word = uresize input.value 32 in
48 | let new_buffer_val =
49 | mux buffer_index.value
50 | [
51 | curr &: of_string "32'h00000000" |: sll curr_byte_word 24;
52 | curr &: of_string "32'hFF000000" |: sll curr_byte_word 16;
53 | curr &: of_string "32'hFFFF0000" |: sll curr_byte_word 8;
54 | curr &: of_string "32'hFFFFFF00" |: curr_byte_word;
55 | ]
56 | in
57 | mux2 should_update_buffer new_buffer_val curr)
58 | in
59 |
60 | Always.(
61 | compile
62 | [
63 | sm.switch
64 | [
65 | ( S_idle,
66 | [
67 | when_ read_enable
68 | [
69 | when_ input.valid
70 | [
71 | buffer_index <-- buffer_index.value +:. 1;
72 | ];
73 | sm.set_next S_wait_next_byte;
74 | ];
75 | ] );
76 | ( S_wait_next_byte,
77 | [
78 | when_ input.valid
79 | [
80 | buffer_index <-- buffer_index.value +:. 1;
81 | when_
82 | (buffer_index.value ==:. 3
83 | |: (input.value ==: of_int ~width:8 newline_hex))
84 | [ sm.set_next S_finished ];
85 | ];
86 | ] );
87 | (S_finished, [ buffer_index <--. 0; sm.set_next S_idle ]);
88 | ];
89 | ]);
90 | let read_busy =
91 | ~:(sm.is S_finished) &: (sm.is S_wait_next_byte |: read_enable)
92 | in
93 | ({ With_valid.valid = sm.is S_finished; value = reg_read_buffer }, read_busy)
94 | end
95 |
96 | module Tx_buffer = struct
97 | module States = struct
98 | type t = S_idle | S_start_of_byte | S_transmitting_byte | S_finished
99 | [@@deriving sexp_of, compare, enumerate]
100 | end
101 |
102 | let create ~clock (input : t Word_with_valid.t) =
103 | let spec = Reg_spec.create ~clock () in
104 |
105 | let reg_write_buffer =
106 | reg_fb spec ~enable:vdd ~width:32 ~f:(fun curr ->
107 | mux2 input.valid input.value curr)
108 | in
109 |
110 | let cycles_width = Base.Int.ceil_log2 cycles_per_packet + 2 in
111 |
112 | let sm = Always.State_machine.create (module States) spec ~enable:vdd in
113 | let read_buffer_index = Always.Variable.reg spec ~enable:vdd ~width:2 in
114 | let tx_cycles_count =
115 | Always.Variable.reg spec ~enable:vdd ~width:cycles_width
116 | in
117 |
118 | Always.(
119 | compile
120 | [
121 | sm.switch
122 | [
123 | ( S_idle,
124 | [
125 | when_ input.valid
126 | [ read_buffer_index <--. 0; sm.set_next S_start_of_byte ];
127 | ] );
128 | ( S_start_of_byte,
129 | [
130 | tx_cycles_count <-- of_int ~width:cycles_width 0;
131 | sm.set_next S_transmitting_byte;
132 | ] );
133 | ( S_transmitting_byte,
134 | [
135 | tx_cycles_count <-- tx_cycles_count.value +:. 1;
136 | when_
137 | (tx_cycles_count.value >=:. cycles_per_packet)
138 | [
139 | read_buffer_index <-- read_buffer_index.value +:. 1;
140 | if_
141 | (read_buffer_index.value ==:. 3)
142 | [ sm.set_next S_finished ]
143 | [ sm.set_next S_start_of_byte ];
144 | ];
145 | ] );
146 | (S_finished, [ read_buffer_index <--. 0; sm.set_next S_idle ]);
147 | ];
148 | ]);
149 | let value =
150 | mux read_buffer_index.value
151 | [
152 | reg_write_buffer.:[(31, 24)];
153 | reg_write_buffer.:[(23, 16)];
154 | reg_write_buffer.:[(15, 8)];
155 | reg_write_buffer.:[(7, 0)];
156 | ]
157 | in
158 | let write_busy =
159 | sm.is S_start_of_byte |: sm.is S_transmitting_byte
160 | |: (input.valid &: ~:(sm.is S_finished))
161 | in
162 | ({ With_valid.valid = sm.is S_start_of_byte; value }, write_busy)
163 | end
164 |
165 | module I = struct
166 | type 'a t = {
167 | clock : 'a; [@bits 1]
168 | write_enable : 'a; [@bits 1]
169 | write_addr : 'a; [@bits 32]
170 | write_data : 'a; [@bits 32]
171 | read_enable : 'a; [@bits 1]
172 | read_addr : 'a; [@bits 32]
173 | uart_rx : 'a Hardcaml_arty.Uart.Byte_with_valid.t; [@rtlprefix "rx_"]
174 | }
175 | [@@deriving sexp_of, hardcaml]
176 | end
177 |
178 | module O = struct
179 | type 'a t = {
180 | io_busy : 'a; [@bits 1]
181 | read_data : 'a; [@bits 32]
182 | uart_tx : 'a Hardcaml_arty.Uart.Byte_with_valid.t; [@rtlprefix "tx_"]
183 | }
184 | [@@deriving sexp_of, hardcaml]
185 | end
186 |
187 | let circuit_impl (_scope : Scope.t) (input : _ I.t) =
188 | let tx, write_busy =
189 | Tx_buffer.create ~clock:input.clock
190 | { With_valid.value = input.write_data; valid = input.write_enable }
191 | in
192 | let rx, read_busy =
193 | Rx_buffer.create ~clock:input.clock ~read_enable:input.read_enable
194 | input.uart_rx
195 | in
196 | let io_busy = write_busy |: read_busy in
197 | { O.read_data = rx.value; io_busy; uart_tx = tx }
198 |
199 | let hierarchical scope input =
200 | let module H = Hierarchy.In_scope (I) (O) in
201 | H.hierarchical ~scope ~name:"uart" circuit_impl input
202 |
--------------------------------------------------------------------------------
/test/instruction_execute/test_instruction_execute.ml:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 | open Hardcaml_waveterm
3 | open Mips.Instruction_execute
4 | module Simulator = Cyclesim.With_interface (I) (O)
5 |
6 | let testbench () =
7 | let scope = Scope.create ~flatten_design:true () in
8 | let sim = Simulator.create (circuit_impl_exn scope) in
9 | let waves, sim = Waveform.create sim in
10 | let inputs = Cyclesim.inputs sim in
11 |
12 | let step ~sel_shift_for_alu ~sel_imm_for_alu ~jal =
13 | inputs.sel_shift_for_alu := Bits.of_string sel_shift_for_alu;
14 | inputs.sel_imm_for_alu := Bits.of_string sel_imm_for_alu;
15 | inputs.alu_a := Bits.of_string "32'h1";
16 | inputs.alu_b := Bits.of_string "32'h2";
17 | inputs.imm := Bits.of_string "32'h183";
18 | inputs.jal := Bits.of_string jal;
19 | inputs.prev2_pc := Bits.of_string "32'h100";
20 | inputs.alu_control := Bits.of_constant (Signal.to_constant Mips.Control_unit.Alu_ops.add);
21 | Cyclesim.cycle sim
22 | in
23 |
24 | step, waves
25 |
26 | let%expect_test "Uses control selector properly for ALU inputs"
27 | =
28 | let step, waves = testbench () in
29 |
30 | let step = step ~jal:"1'b0" in
31 |
32 | step ~sel_shift_for_alu:"1'b0" ~sel_imm_for_alu:"1'b0";
33 | step ~sel_shift_for_alu:"1'b0" ~sel_imm_for_alu:"1'b1";
34 | step ~sel_shift_for_alu:"1'b1" ~sel_imm_for_alu:"1'b0";
35 | step ~sel_shift_for_alu:"1'b1" ~sel_imm_for_alu:"1'b1";
36 |
37 | Waveform.print ~wave_width:4 ~display_height:30 ~display_width:90 waves;
38 | [%expect
39 | {|
40 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐
41 | │ ││──────────────────────────────────────── │
42 | │alu_a ││ 00000001 │
43 | │ ││──────────────────────────────────────── │
44 | │ ││──────────────────────────────────────── │
45 | │alu_b ││ 00000002 │
46 | │ ││──────────────────────────────────────── │
47 | │ ││──────────────────────────────────────── │
48 | │alu_control ││ 02 │
49 | │ ││──────────────────────────────────────── │
50 | │ ││──────────────────────────────────────── │
51 | │imm ││ 00000183 │
52 | │ ││──────────────────────────────────────── │
53 | │jal ││ │
54 | │ ││──────────────────────────────────────── │
55 | │ ││──────────────────────────────────────── │
56 | │prev2_pc ││ 00000100 │
57 | │ ││──────────────────────────────────────── │
58 | │sel_imm_for_alu ││ ┌─────────┐ ┌───────── │
59 | │ ││──────────┘ └─────────┘ │
60 | │sel_shift_for_alu ││ ┌─────────────────── │
61 | │ ││────────────────────┘ │
62 | │ ││──────────┬─────────┬─────────┬───────── │
63 | │alu_result ││ 00000003 │00000184 │00000008 │00000189 │
64 | │ ││──────────┴─────────┴─────────┴───────── │
65 | │ ││ │
66 | │ ││ │
67 | │ ││ │
68 | │ ││ │
69 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘
70 | |}]
71 |
72 | let%expect_test "jal mux"
73 | =
74 | let step, waves = testbench () in
75 |
76 | let step = step ~jal:"1'b1" in
77 |
78 | step ~sel_shift_for_alu:"1'b0" ~sel_imm_for_alu:"1'b0";
79 | step ~sel_shift_for_alu:"1'b0" ~sel_imm_for_alu:"1'b1";
80 | step ~sel_shift_for_alu:"1'b1" ~sel_imm_for_alu:"1'b0";
81 | step ~sel_shift_for_alu:"1'b1" ~sel_imm_for_alu:"1'b1";
82 |
83 | Waveform.print ~wave_width:4 ~display_height:30 ~display_width:90 waves;
84 | [%expect
85 | {|
86 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐
87 | │ ││──────────────────────────────────────── │
88 | │alu_a ││ 00000001 │
89 | │ ││──────────────────────────────────────── │
90 | │ ││──────────────────────────────────────── │
91 | │alu_b ││ 00000002 │
92 | │ ││──────────────────────────────────────── │
93 | │ ││──────────────────────────────────────── │
94 | │alu_control ││ 02 │
95 | │ ││──────────────────────────────────────── │
96 | │ ││──────────────────────────────────────── │
97 | │imm ││ 00000183 │
98 | │ ││──────────────────────────────────────── │
99 | │jal ││──────────────────────────────────────── │
100 | │ ││ │
101 | │ ││──────────────────────────────────────── │
102 | │prev2_pc ││ 00000100 │
103 | │ ││──────────────────────────────────────── │
104 | │sel_imm_for_alu ││ ┌─────────┐ ┌───────── │
105 | │ ││──────────┘ └─────────┘ │
106 | │sel_shift_for_alu ││ ┌─────────────────── │
107 | │ ││────────────────────┘ │
108 | │ ││──────────────────────────────────────── │
109 | │alu_result ││ 00000108 │
110 | │ ││──────────────────────────────────────── │
111 | │ ││ │
112 | │ ││ │
113 | │ ││ │
114 | │ ││ │
115 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘
116 | |}]
117 |
--------------------------------------------------------------------------------
/arty/ips/design_1_clk_wiz_0_0/design_1_clk_wiz_0_0_clk_wiz.v:
--------------------------------------------------------------------------------
1 |
2 | // file: design_1_clk_wiz_0_0.v
3 | //
4 | // (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved.
5 | //
6 | // This file contains confidential and proprietary information
7 | // of Xilinx, Inc. and is protected under U.S. and
8 | // international copyright and other intellectual property
9 | // laws.
10 | //
11 | // DISCLAIMER
12 | // This disclaimer is not a license and does not grant any
13 | // rights to the materials distributed herewith. Except as
14 | // otherwise provided in a valid license issued to you by
15 | // Xilinx, and to the maximum extent permitted by applicable
16 | // law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
17 | // WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
18 | // AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
19 | // BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
20 | // INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
21 | // (2) Xilinx shall not be liable (whether in contract or tort,
22 | // including negligence, or under any other theory of
23 | // liability) for any loss or damage of any kind or nature
24 | // related to, arising under or in connection with these
25 | // materials, including for any direct, or any indirect,
26 | // special, incidental, or consequential loss or damage
27 | // (including loss of data, profits, goodwill, or any type of
28 | // loss or damage suffered as a result of any action brought
29 | // by a third party) even if such damage or loss was
30 | // reasonably foreseeable or Xilinx had been advised of the
31 | // possibility of the same.
32 | //
33 | // CRITICAL APPLICATIONS
34 | // Xilinx products are not designed or intended to be fail-
35 | // safe, or for use in any application requiring fail-safe
36 | // performance, such as life-support or safety devices or
37 | // systems, Class III medical devices, nuclear facilities,
38 | // applications related to the deployment of airbags, or any
39 | // other applications that could lead to death, personal
40 | // injury, or severe property or environmental damage
41 | // (individually and collectively, "Critical
42 | // Applications"). Customer assumes the sole risk and
43 | // liability of any use of Xilinx products in Critical
44 | // Applications, subject only to applicable laws and
45 | // regulations governing limitations on product liability.
46 | //
47 | // THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
48 | // PART OF THIS FILE AT ALL TIMES.
49 | //
50 | //----------------------------------------------------------------------------
51 | // User entered comments
52 | //----------------------------------------------------------------------------
53 | // None
54 | //
55 | //----------------------------------------------------------------------------
56 | // Output Output Phase Duty Cycle Pk-to-Pk Phase
57 | // Clock Freq (MHz) (degrees) (%) Jitter (ps) Error (ps)
58 | //----------------------------------------------------------------------------
59 | // clk_out1__166.66667______0.000______50.0______118.758_____98.575
60 | // clk_out2__200.00000______0.000______50.0______114.829_____98.575
61 | // clk_out3__25.00000______0.000______50.0______175.402_____98.575
62 | //
63 | //----------------------------------------------------------------------------
64 | // Input Clock Freq (MHz) Input Jitter (UI)
65 | //----------------------------------------------------------------------------
66 | // __primary_________100.000____________0.010
67 |
68 | `timescale 1ps/1ps
69 |
70 | module design_1_clk_wiz_0_0_clk_wiz
71 |
72 | (// Clock in ports
73 | // Clock out ports
74 | output clk_out1,
75 | output clk_out2,
76 | output clk_out3,
77 | // Status and control signals
78 | input resetn,
79 | output locked,
80 | input clk_in1
81 | );
82 | // Input buffering
83 | //------------------------------------
84 | wire clk_in1_design_1_clk_wiz_0_0;
85 | wire clk_in2_design_1_clk_wiz_0_0;
86 | IBUF clkin1_ibufg
87 | (.O (clk_in1_design_1_clk_wiz_0_0),
88 | .I (clk_in1));
89 |
90 |
91 |
92 |
93 | // Clocking PRIMITIVE
94 | //------------------------------------
95 |
96 | // Instantiation of the MMCM PRIMITIVE
97 | // * Unused inputs are tied off
98 | // * Unused outputs are labeled unused
99 |
100 | wire clk_out1_design_1_clk_wiz_0_0;
101 | wire clk_out2_design_1_clk_wiz_0_0;
102 | wire clk_out3_design_1_clk_wiz_0_0;
103 | wire clk_out4_design_1_clk_wiz_0_0;
104 | wire clk_out5_design_1_clk_wiz_0_0;
105 | wire clk_out6_design_1_clk_wiz_0_0;
106 | wire clk_out7_design_1_clk_wiz_0_0;
107 |
108 | wire [15:0] do_unused;
109 | wire drdy_unused;
110 | wire psdone_unused;
111 | wire locked_int;
112 | wire clkfbout_design_1_clk_wiz_0_0;
113 | wire clkfbout_buf_design_1_clk_wiz_0_0;
114 | wire clkfboutb_unused;
115 | wire clkout0b_unused;
116 | wire clkout1b_unused;
117 | wire clkout2b_unused;
118 | wire clkout3_unused;
119 | wire clkout3b_unused;
120 | wire clkout4_unused;
121 | wire clkout5_unused;
122 | wire clkout6_unused;
123 | wire clkfbstopped_unused;
124 | wire clkinstopped_unused;
125 | wire reset_high;
126 |
127 | MMCME2_ADV
128 | #(.BANDWIDTH ("OPTIMIZED"),
129 | .CLKOUT4_CASCADE ("FALSE"),
130 | .COMPENSATION ("ZHOLD"),
131 | .STARTUP_WAIT ("FALSE"),
132 | .DIVCLK_DIVIDE (1),
133 | .CLKFBOUT_MULT_F (10.000),
134 | .CLKFBOUT_PHASE (0.000),
135 | .CLKFBOUT_USE_FINE_PS ("FALSE"),
136 | .CLKOUT0_DIVIDE_F (6.000),
137 | .CLKOUT0_PHASE (0.000),
138 | .CLKOUT0_DUTY_CYCLE (0.500),
139 | .CLKOUT0_USE_FINE_PS ("FALSE"),
140 | .CLKOUT1_DIVIDE (5),
141 | .CLKOUT1_PHASE (0.000),
142 | .CLKOUT1_DUTY_CYCLE (0.500),
143 | .CLKOUT1_USE_FINE_PS ("FALSE"),
144 | .CLKOUT2_DIVIDE (40),
145 | .CLKOUT2_PHASE (0.000),
146 | .CLKOUT2_DUTY_CYCLE (0.500),
147 | .CLKOUT2_USE_FINE_PS ("FALSE"),
148 | .CLKIN1_PERIOD (10.000))
149 | mmcm_adv_inst
150 | // Output clocks
151 | (
152 | .CLKFBOUT (clkfbout_design_1_clk_wiz_0_0),
153 | .CLKFBOUTB (clkfboutb_unused),
154 | .CLKOUT0 (clk_out1_design_1_clk_wiz_0_0),
155 | .CLKOUT0B (clkout0b_unused),
156 | .CLKOUT1 (clk_out2_design_1_clk_wiz_0_0),
157 | .CLKOUT1B (clkout1b_unused),
158 | .CLKOUT2 (clk_out3_design_1_clk_wiz_0_0),
159 | .CLKOUT2B (clkout2b_unused),
160 | .CLKOUT3 (clkout3_unused),
161 | .CLKOUT3B (clkout3b_unused),
162 | .CLKOUT4 (clkout4_unused),
163 | .CLKOUT5 (clkout5_unused),
164 | .CLKOUT6 (clkout6_unused),
165 | // Input clock control
166 | .CLKFBIN (clkfbout_buf_design_1_clk_wiz_0_0),
167 | .CLKIN1 (clk_in1_design_1_clk_wiz_0_0),
168 | .CLKIN2 (1'b0),
169 | // Tied to always select the primary input clock
170 | .CLKINSEL (1'b1),
171 | // Ports for dynamic reconfiguration
172 | .DADDR (7'h0),
173 | .DCLK (1'b0),
174 | .DEN (1'b0),
175 | .DI (16'h0),
176 | .DO (do_unused),
177 | .DRDY (drdy_unused),
178 | .DWE (1'b0),
179 | // Ports for dynamic phase shift
180 | .PSCLK (1'b0),
181 | .PSEN (1'b0),
182 | .PSINCDEC (1'b0),
183 | .PSDONE (psdone_unused),
184 | // Other control and status signals
185 | .LOCKED (locked_int),
186 | .CLKINSTOPPED (clkinstopped_unused),
187 | .CLKFBSTOPPED (clkfbstopped_unused),
188 | .PWRDWN (1'b0),
189 | .RST (reset_high));
190 | assign reset_high = ~resetn;
191 |
192 | assign locked = locked_int;
193 | // Clock Monitor clock assigning
194 | //--------------------------------------
195 | // Output buffering
196 | //-----------------------------------
197 |
198 | BUFG clkf_buf
199 | (.O (clkfbout_buf_design_1_clk_wiz_0_0),
200 | .I (clkfbout_design_1_clk_wiz_0_0));
201 |
202 |
203 |
204 |
205 |
206 |
207 | BUFG clkout1_buf
208 | (.O (clk_out1),
209 | .I (clk_out1_design_1_clk_wiz_0_0));
210 |
211 |
212 | BUFG clkout2_buf
213 | (.O (clk_out2),
214 | .I (clk_out2_design_1_clk_wiz_0_0));
215 |
216 | BUFG clkout3_buf
217 | (.O (clk_out3),
218 | .I (clk_out3_design_1_clk_wiz_0_0));
219 |
220 |
221 |
222 | endmodule
223 |
--------------------------------------------------------------------------------
/arty/boards/arty-a7-35/E.0/part0_pins.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
--------------------------------------------------------------------------------
/arty/boards/arty-a7-35/E.0/mig.prj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | design_1_mig_7series_0_0
5 | 1
6 | 1
7 | OFF
8 | 1024
9 | ON
10 | Enabled
11 | xc7a35ti-csg324/-1L
12 | 2.3
13 | No Buffer
14 | No Buffer
15 | ACTIVE LOW
16 | FALSE
17 | 1
18 | 50 Ohms
19 | 0
20 |
21 | DDR3_SDRAM/Components/MT41K128M16XX-15E
22 | 3000
23 | 1.8V
24 | 4:1
25 | 166.666
26 | 0
27 | 666
28 | 1.000
29 | 1
30 | 1
31 | 1
32 | 1
33 | 16
34 | 1
35 | 1
36 | Disabled
37 | Normal
38 | FALSE
39 |
40 | 14
41 | 10
42 | 3
43 | 1.35V
44 | 268435456
45 | BANK_ROW_COLUMN
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 | 8 - Fixed
105 | Sequential
106 | 5
107 | Normal
108 | No
109 | Slow Exit
110 | Enable
111 | RZQ/6
112 | Disable
113 | Enable
114 | RZQ/6
115 | 0
116 | Disabled
117 | Enabled
118 | Output Buffer Enabled
119 | Full Array
120 | 5
121 | Enabled
122 | Normal
123 | Dynamic ODT off
124 | AXI
125 |
126 | RD_PRI_REG
127 | 28
128 | 128
129 | 4
130 | 0
131 |
132 |
133 |
134 |
135 |
--------------------------------------------------------------------------------
/arty/ips/design_1_clk_wiz_0_0/doc/clk_wiz_v6_0_changelog.txt:
--------------------------------------------------------------------------------
1 | 2021.2:
2 | * Version 6.0 (Rev. 9)
3 | * Bug Fix: CR Fixes
4 | * Other: CR Fixes
5 |
6 | 2021.1.1:
7 | * Version 6.0 (Rev. 8)
8 | * No changes
9 |
10 | 2021.1:
11 | * Version 6.0 (Rev. 8)
12 | * Bug Fix: Internal GUI fixes
13 | * Other: CR Fixes
14 |
15 | 2020.3:
16 | * Version 6.0 (Rev. 7)
17 | * Bug Fix: Internal GUI fixes
18 | * Other: CR Fixes
19 |
20 | 2020.2.2:
21 | * Version 6.0 (Rev. 6)
22 | * No changes
23 |
24 | 2020.2.1:
25 | * Version 6.0 (Rev. 6)
26 | * No changes
27 |
28 | 2020.2:
29 | * Version 6.0 (Rev. 6)
30 | * Bug Fix: Internal GUI fixes
31 | * Other: CR Fixes
32 |
33 | 2020.1.1:
34 | * Version 6.0 (Rev. 5)
35 | * No changes
36 |
37 | 2020.1:
38 | * Version 6.0 (Rev. 5)
39 | * Bug Fix: Internal GUI fixes
40 | * Other: CR Fixes
41 |
42 | 2019.2.2:
43 | * Version 6.0 (Rev. 4)
44 | * No changes
45 |
46 | 2019.2.1:
47 | * Version 6.0 (Rev. 4)
48 | * No changes
49 |
50 | 2019.2:
51 | * Version 6.0 (Rev. 4)
52 | * Bug Fix: Internal GUI fixes
53 | * Other: CR Fixes
54 |
55 | 2019.1.3:
56 | * Version 6.0 (Rev. 3)
57 | * No changes
58 |
59 | 2019.1.2:
60 | * Version 6.0 (Rev. 3)
61 | * No changes
62 |
63 | 2019.1.1:
64 | * Version 6.0 (Rev. 3)
65 | * No changes
66 |
67 | 2019.1:
68 | * Version 6.0 (Rev. 3)
69 | * Bug Fix: Internal GUI fixes
70 | * Other: New family support added
71 |
72 | 2018.3.1:
73 | * Version 6.0 (Rev. 2)
74 | * No changes
75 |
76 | 2018.3:
77 | * Version 6.0 (Rev. 2)
78 | * Bug Fix: Made input source independent for primary and secondary clock
79 | * Other: New family support added
80 |
81 | 2018.2:
82 | * Version 6.0 (Rev. 1)
83 | * Bug Fix: Removed vco freq check when Primitive is None
84 | * Other: New family support added
85 |
86 | 2018.1:
87 | * Version 6.0
88 | * Bug Fix: Bug fixes in Dynamic Reconfiguration feature and Write DRP feature
89 | * Bug Fix: Bug fixes for connection issue for s_axi_aresetn pin in IPI
90 | * Feature Enhancement: The default value of USE_PHASE_ALIGMENT is updated to false for UltraScale and UltraScale+ devices. Phase Alignment feature uses extra clock routes in UltraScale and UltraScale+ designs when MMCMs are used. These routing resources are wasted when user do not understand when phase alignment is really needed. Now, implementation tools can use these extra clock routing resources for high fanout signals.
91 | * Feature Enhancement: A column "Max. freq of buffer" is added in the Output Clock table which shows the maximum frequency that the selected output buffer can support
92 | * Other: DRCs added for invalid input values in Override mode
93 |
94 | 2017.4:
95 | * Version 5.4 (Rev. 3)
96 | * Bug Fix: Internal GUI issues are fixed for COMPENSATION mode as INTERNAL
97 | * Bug Fix: Fixed issue in dynamic reconfiguration of fractional values of M in MMCME3, MMCME4
98 |
99 | 2017.3:
100 | * Version 5.4 (Rev. 2)
101 | * General: Internal GUI changes. No effect on the customer design. Added support for aspartan7 devices
102 |
103 | 2017.2:
104 | * Version 5.4 (Rev. 1)
105 | * General: Internal GUI changes. No effect on the customer design.
106 |
107 | 2017.1:
108 | * Version 5.4
109 | * Port Change: Minor version upgrade. CLR pins are added to the pin list when selected buffer is BUFGCEDIV for ultrascale and ultrascale plus devices.
110 | * Other: Added support for new zynq ultrascale plus devices.
111 |
112 | 2016.4:
113 | * Version 5.3 (Rev. 3)
114 | * Bug Fix: Internal GUI issues are fixed.
115 |
116 | 2016.3:
117 | * Version 5.3 (Rev. 2)
118 | * Feature Enhancement: Added new option "Auto" under PRIMITIVE selection for ultrascale and above devices. This option allows the Wizard to instantiate appropriate primitive for the user inputs.
119 | * Feature Enhancement: Added Matched Routing Option for better timing solutions.
120 | * Feature Enhancement: Options 'Buffer' and 'Buffer_with_CE' are added to the buffer selection list.
121 | * Other: Source HDL files are concatenated into a single file to speed up synthesis and simulation. No changes required by the user
122 | * Other: Added support for Spartan7 devices.
123 |
124 | 2016.2:
125 | * Version 5.3 (Rev. 1)
126 | * Internal register bit update, no effect on customer designs.
127 |
128 | 2016.1:
129 | * Version 5.3
130 | * Added Clock Monitor Feature as part of clocking wizard
131 | * DRP registers can be directly written through AXI without resource utilization
132 | * Changes to HDL library management to support Vivado IP simulation library
133 |
134 | 2015.4.2:
135 | * Version 5.2 (Rev. 1)
136 | * No changes
137 |
138 | 2015.4.1:
139 | * Version 5.2 (Rev. 1)
140 | * No changes
141 |
142 | 2015.4:
143 | * Version 5.2 (Rev. 1)
144 | * Internal device family change, no functional changes
145 |
146 | 2015.3:
147 | * Version 5.2
148 | * IP revision number added to HDL module, library, and include file names, to support designs with both locked and upgraded IP instances
149 | * Port Renaming tab is hidden in the GUI in IP Integrator as this feature is not supported
150 | * Phase alignment feature is removed for ultrascale PLL as primitve has limited capabilities of supporting this feature
151 | * When clocking wizard is targetted on a board part, the frequency values that gets propagated to primary and secondary clocks are displayed in floating number format
152 | * Example design and simulation files are delivered in verilog only
153 |
154 | 2015.2.1:
155 | * Version 5.1 (Rev. 6)
156 | * No changes
157 |
158 | 2015.2:
159 | * Version 5.1 (Rev. 6)
160 | * No changes
161 |
162 | 2015.1:
163 | * Version 5.1 (Rev. 6)
164 | * Updated mmcm_pll_filter_lookup and mmcm_pll_lock_lookup functions in the header file for 7-Series and UltraScale devices
165 | * Supported devices and production status are now determined automatically, to simplify support for future devices
166 |
167 | 2014.4.1:
168 | * Version 5.1 (Rev. 5)
169 | * No changes
170 |
171 | 2014.4:
172 | * Version 5.1 (Rev. 5)
173 | * Internal device family change, no functional changes
174 | * updates related to the source selection based on board interface for zed board
175 |
176 | 2014.3:
177 | * Version 5.1 (Rev. 4)
178 | * Option added to enable dynamic phase and duty cycle for resource optimization in AXI4-Lite interface
179 |
180 | 2014.2:
181 | * Version 5.1 (Rev. 3)
182 | * Updated for AXI4-Lite interface locked status register address and bit mapping to align with the pg065
183 |
184 | 2014.1:
185 | * Version 5.1 (Rev. 2)
186 | * Updated to use inverted output CLKOUTB 0-3 of Clocking Primitive based on requested 180 phase w.r.t. previous clock
187 | * Internal device family name change, no functional changes
188 |
189 | 2013.4:
190 | * Version 5.1 (Rev. 1)
191 | * Added support for Ultrascale devices
192 | * Updated Board Flow GUI to select the clock interfaces
193 | * Fixed issue with Stub file parameter error for BUFR output driver
194 |
195 | 2013.3:
196 | * Version 5.1
197 | * Added AXI4-Lite interface to dynamically reconfigure MMCM/PLL
198 | * Improved safe clock logic to remove glitches on clock outputs for odd multiples of input clock frequencies
199 | * Fixed precision issues between displayed and actual frequencies
200 | * Added tool tips to GUI
201 | * Added Jitter and Phase error values to IP properties
202 | * Added support for Cadence IES and Synopsys VCS simulators
203 | * Reduced warnings in synthesis and simulation
204 | * Enhanced support for IP Integrator
205 |
206 | 2013.2:
207 | * Version 5.0 (Rev. 1)
208 | * Fixed issue with clock constraints for multiple instances of clocking wizard
209 | * Updated Life-Cycle status of devices
210 |
211 | 2013.1:
212 | * Version 5.0
213 | * Lower case ports for Verilog
214 | * Added Safe Clock Startup and Clock Sequencing
215 |
216 | (c) Copyright 2008 - 2021 Xilinx, Inc. All rights reserved.
217 |
218 | This file contains confidential and proprietary information
219 | of Xilinx, Inc. and is protected under U.S. and
220 | international copyright and other intellectual property
221 | laws.
222 |
223 | DISCLAIMER
224 | This disclaimer is not a license and does not grant any
225 | rights to the materials distributed herewith. Except as
226 | otherwise provided in a valid license issued to you by
227 | Xilinx, and to the maximum extent permitted by applicable
228 | law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
229 | WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
230 | AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
231 | BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
232 | INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
233 | (2) Xilinx shall not be liable (whether in contract or tort,
234 | including negligence, or under any other theory of
235 | liability) for any loss or damage of any kind or nature
236 | related to, arising under or in connection with these
237 | materials, including for any direct, or any indirect,
238 | special, incidental, or consequential loss or damage
239 | (including loss of data, profits, goodwill, or any type of
240 | loss or damage suffered as a result of any action brought
241 | by a third party) even if such damage or loss was
242 | reasonably foreseeable or Xilinx had been advised of the
243 | possibility of the same.
244 |
245 | CRITICAL APPLICATIONS
246 | Xilinx products are not designed or intended to be fail-
247 | safe, or for use in any application requiring fail-safe
248 | performance, such as life-support or safety devices or
249 | systems, Class III medical devices, nuclear facilities,
250 | applications related to the deployment of airbags, or any
251 | other applications that could lead to death, personal
252 | injury, or severe property or environmental damage
253 | (individually and collectively, "Critical
254 | Applications"). Customer assumes the sole risk and
255 | liability of any use of Xilinx products in Critical
256 | Applications, subject only to applicable laws and
257 | regulations governing limitations on product liability.
258 |
259 | THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
260 | PART OF THIS FILE AT ALL TIMES.
261 |
--------------------------------------------------------------------------------
/test/io/uart/test_uart_tx.ml:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 | open Hardcaml_waveterm
3 |
4 | let clock = Signal.input "clock" 1
5 |
6 | let waves =
7 | let valid = Signal.input "valid" 1 in
8 | let value = Signal.input "value" 32 in
9 | let tx, tx_busy = Mips.Uart.Tx_buffer.create ~clock { valid; value } in
10 | let uart_tx_value = Signal.output "uart_tx_value" tx.value in
11 | let uart_tx_valid = Signal.output "uart_tx_valid" tx.valid in
12 | let uart_tx_busy = Signal.output "uart_tx_busy" tx_busy in
13 | let circuit =
14 | Circuit.create_exn ~name:"tx_state_machine" [ uart_tx_value; uart_tx_valid; uart_tx_busy ]
15 | in
16 | let waves, sim =
17 | Hardcaml_waveterm.Waveform.create
18 | (Cyclesim.create ~config:Cyclesim.Config.trace_all circuit)
19 | in
20 | Cyclesim.cycle sim;
21 | Cyclesim.cycle sim;
22 | Cyclesim.in_port sim "valid" := Bits.vdd;
23 | Cyclesim.in_port sim "value" := Bits.of_string "32'h61727479" (* "arty" *);
24 | Cyclesim.cycle sim;
25 | Cyclesim.in_port sim "valid" := Bits.gnd;
26 | for _ = 0 to Mips.Uart.cycles_per_packet * 5 do
27 | Cyclesim.cycle sim
28 | done;
29 | waves
30 |
31 | let%expect_test "tx_first_byte" =
32 | Waveform.print ~display_width:100 ~display_height:16 waves;
33 | [%expect
34 | {|
35 | ┌Signals───────────┐┌Waves─────────────────────────────────────────────────────────────────────────┐
36 | │clock ││┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │
37 | │ ││ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └─│
38 | │valid ││ ┌───────┐ │
39 | │ ││────────────────┘ └─────────────────────────────────────────────────────│
40 | │ ││────────────────┬─────────────────────────────────────────────────────────────│
41 | │value ││ 00000000 │61727479 │
42 | │ ││────────────────┴─────────────────────────────────────────────────────────────│
43 | │uart_tx_busy ││ ┌─────────────────────────────────────────────────────────────│
44 | │ ││────────────────┘ │
45 | │uart_tx_valid ││ ┌───────┐ │
46 | │ ││────────────────────────┘ └─────────────────────────────────────────────│
47 | │ ││────────────────────────┬─────────────────────────────────────────────────────│
48 | │uart_tx_value ││ 00 │61 │
49 | │ ││────────────────────────┴─────────────────────────────────────────────────────│
50 | └──────────────────┘└──────────────────────────────────────────────────────────────────────────────┘ |}]
51 |
52 | let%expect_test "tx_second_byte" =
53 | Waveform.print ~start_cycle:Mips.Uart.cycles_per_packet ~display_width:100
54 | ~display_height:16 waves;
55 | [%expect
56 | {|
57 | ┌Signals───────────┐┌Waves─────────────────────────────────────────────────────────────────────────┐
58 | │clock ││┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │
59 | │ ││ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └─│
60 | │valid ││ │
61 | │ ││──────────────────────────────────────────────────────────────────────────────│
62 | │ ││──────────────────────────────────────────────────────────────────────────────│
63 | │value ││ 61727479 │
64 | │ ││──────────────────────────────────────────────────────────────────────────────│
65 | │uart_tx_busy ││──────────────────────────────────────────────────────────────────────────────│
66 | │ ││ │
67 | │uart_tx_valid ││ ┌───────┐ │
68 | │ ││────────────────────────────────────────┘ └─────────────────────────────│
69 | │ ││────────────────────────────────────────┬─────────────────────────────────────│
70 | │uart_tx_value ││ 61 │72 │
71 | │ ││────────────────────────────────────────┴─────────────────────────────────────│
72 | └──────────────────┘└──────────────────────────────────────────────────────────────────────────────┘ |}]
73 |
74 | let%expect_test "tx_third_byte" =
75 | Waveform.print
76 | ~start_cycle:(Mips.Uart.cycles_per_packet * 2)
77 | ~display_width:100 ~display_height:16 waves;
78 | [%expect
79 | {|
80 | ┌Signals───────────┐┌Waves─────────────────────────────────────────────────────────────────────────┐
81 | │clock ││┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │
82 | │ ││ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └─│
83 | │valid ││ │
84 | │ ││──────────────────────────────────────────────────────────────────────────────│
85 | │ ││──────────────────────────────────────────────────────────────────────────────│
86 | │value ││ 61727479 │
87 | │ ││──────────────────────────────────────────────────────────────────────────────│
88 | │uart_tx_busy ││──────────────────────────────────────────────────────────────────────────────│
89 | │ ││ │
90 | │uart_tx_valid ││ ┌───────┐ │
91 | │ ││────────────────────────────────────────────────────────┘ └─────────────│
92 | │ ││────────────────────────────────────────────────────────┬─────────────────────│
93 | │uart_tx_value ││ 72 │74 │
94 | │ ││────────────────────────────────────────────────────────┴─────────────────────│
95 | └──────────────────┘└──────────────────────────────────────────────────────────────────────────────┘ |}]
96 |
97 | let%expect_test "tx_fourth_byte" =
98 | Waveform.print
99 | ~start_cycle:(Mips.Uart.cycles_per_packet * 3 + 3)
100 | ~display_width:100 ~display_height:16 waves;
101 | [%expect
102 | {|
103 | ┌Signals───────────┐┌Waves─────────────────────────────────────────────────────────────────────────┐
104 | │clock ││┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │
105 | │ ││ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └─│
106 | │valid ││ │
107 | │ ││──────────────────────────────────────────────────────────────────────────────│
108 | │ ││──────────────────────────────────────────────────────────────────────────────│
109 | │value ││ 61727479 │
110 | │ ││──────────────────────────────────────────────────────────────────────────────│
111 | │uart_tx_busy ││──────────────────────────────────────────────────────────────────────────────│
112 | │ ││ │
113 | │uart_tx_valid ││ ┌───────┐ │
114 | │ ││────────────────────────────────────────────────┘ └─────────────────────│
115 | │ ││────────────────────────────────────────────────┬─────────────────────────────│
116 | │uart_tx_value ││ 74 │79 │
117 | │ ││────────────────────────────────────────────────┴─────────────────────────────│
118 | └──────────────────┘└──────────────────────────────────────────────────────────────────────────────┘ |}]
119 |
120 |
121 | let%expect_test "tx_fifth_byte (should stop transmitting)" =
122 | Waveform.print
123 | ~start_cycle:(Mips.Uart.cycles_per_packet * 4 + 4)
124 | ~display_width:120 ~display_height:16 waves;
125 | [%expect
126 | {|
127 | ┌Signals───────────┐┌Waves─────────────────────────────────────────────────────────────────────────────────────────────┐
128 | │clock ││┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─│
129 | │ ││ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ └───┘ │
130 | │valid ││ │
131 | │ ││──────────────────────────────────────────────────────────────────────────────────────────────────│
132 | │ ││──────────────────────────────────────────────────────────────────────────────────────────────────│
133 | │value ││ 61727479 │
134 | │ ││──────────────────────────────────────────────────────────────────────────────────────────────────│
135 | │uart_tx_busy ││────────────────────────────────────────────────────────┐ │
136 | │ ││ └─────────────────────────────────────────│
137 | │uart_tx_valid ││ │
138 | │ ││──────────────────────────────────────────────────────────────────────────────────────────────────│
139 | │ ││────────────────────────────────────────────────────────┬─────────────────────────────────────────│
140 | │uart_tx_value ││ 79 │61 │
141 | │ ││────────────────────────────────────────────────────────┴─────────────────────────────────────────│
142 | └──────────────────┘└──────────────────────────────────────────────────────────────────────────────────────────────────┘ |}]
143 |
--------------------------------------------------------------------------------
/test/io/test_delay_test_io.ml:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 | open Hardcaml_waveterm
3 | open Mips.Delay_test_io
4 | module Simulator = Cyclesim.With_interface (I) (O)
5 |
6 | let testbench enableds =
7 | let scope = Scope.create ~flatten_design:true () in
8 | let sim = Simulator.create (circuit_impl scope) in
9 | let waves, sim = Waveform.create sim in
10 | let inputs = Cyclesim.inputs sim in
11 |
12 | let step read_enabled write_enabled =
13 | inputs.read_enable := Bits.of_bool read_enabled;
14 | inputs.write_enable := Bits.of_bool write_enabled;
15 | Cyclesim.cycle sim
16 | in
17 |
18 | List.iter
19 | (fun (read_enabled, write_enabled) -> step read_enabled write_enabled)
20 | enableds;
21 |
22 | waves
23 |
24 | let%expect_test "stays in not stalling state if nothing happens" =
25 | let pattern =
26 | [
27 | (false, false);
28 | (false, false);
29 | (false, false);
30 | (false, false);
31 | (false, false);
32 | (false, false);
33 | ]
34 | in
35 | let waves = testbench pattern in
36 | Waveform.print ~wave_width:4 ~display_width:90 ~display_height:13 waves;
37 | [%expect
38 | {|
39 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐
40 | │clock ││┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
41 | │ ││ └────┘ └────┘ └────┘ └────┘ └────┘ └────┘ └──│
42 | │read_enable ││ │
43 | │ ││──────────────────────────────────────────────────────────── │
44 | │write_enable ││ │
45 | │ ││──────────────────────────────────────────────────────────── │
46 | │io_busy ││ │
47 | │ ││──────────────────────────────────────────────────────────── │
48 | │ ││──────────────────────────────────────────────────────────── │
49 | │read_data ││ 00000000 │
50 | │ ││──────────────────────────────────────────────────────────── │
51 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}]
52 |
53 | let%expect_test "stalls for correct number of cycles if write happens" =
54 | let pattern =
55 | [
56 | (false, false);
57 | (false, true);
58 | (false, false);
59 | (false, false);
60 | (false, false);
61 | (false, false);
62 | ]
63 | in
64 | let waves = testbench pattern in
65 | Waveform.print ~wave_width:4 ~display_width:90 ~display_height:13 waves;
66 | [%expect
67 | {|
68 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐
69 | │clock ││┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
70 | │ ││ └────┘ └────┘ └────┘ └────┘ └────┘ └────┘ └──│
71 | │read_enable ││ │
72 | │ ││──────────────────────────────────────────────────────────── │
73 | │write_enable ││ ┌─────────┐ │
74 | │ ││──────────┘ └─────────────────────────────────────── │
75 | │io_busy ││ ┌───────────────────────────────────────┐ │
76 | │ ││──────────┘ └───────── │
77 | │ ││──────────────────────────────────────────────────────────── │
78 | │read_data ││ 00000000 │
79 | │ ││──────────────────────────────────────────────────────────── │
80 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}]
81 |
82 | let%expect_test "stalls for correct number of cycles if read and write happen \
83 | concurrently" =
84 | let pattern =
85 | [
86 | (false, false);
87 | (true, true);
88 | (false, false);
89 | (false, false);
90 | (false, false);
91 | (false, false);
92 | ]
93 | in
94 | let waves = testbench pattern in
95 | Waveform.print ~wave_width:4 ~display_width:90 ~display_height:13 waves;
96 | [%expect
97 | {|
98 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐
99 | │clock ││┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
100 | │ ││ └────┘ └────┘ └────┘ └────┘ └────┘ └────┘ └──│
101 | │read_enable ││ ┌─────────┐ │
102 | │ ││──────────┘ └─────────────────────────────────────── │
103 | │write_enable ││ ┌─────────┐ │
104 | │ ││──────────┘ └─────────────────────────────────────── │
105 | │io_busy ││ ┌───────────────────────────────────────┐ │
106 | │ ││──────────┘ └───────── │
107 | │ ││──────────────────────────────┬─────────┬─────────────────── │
108 | │read_data ││ 00000000 │0000001E │00000000 │
109 | │ ││──────────────────────────────┴─────────┴─────────────────── │
110 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}]
111 |
112 | let%expect_test "stalls for correct number of cycles when reads not back to \
113 | back" =
114 | let pattern =
115 | [
116 | (false, false);
117 | (true, false);
118 | (false, false);
119 | (false, false);
120 | (true, false);
121 | (false, false);
122 | (false, false);
123 | (false, false);
124 | ]
125 | in
126 | let waves = testbench pattern in
127 | Waveform.print ~wave_width:4 ~display_width:90 ~display_height:13 waves;
128 | [%expect
129 | {|
130 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐
131 | │clock ││┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
132 | │ ││ └────┘ └────┘ └────┘ └────┘ └────┘ └────┘ └──│
133 | │read_enable ││ ┌─────────┐ ┌─────────┐ │
134 | │ ││──────────┘ └───────────────────┘ └─────────────────│
135 | │write_enable ││ │
136 | │ ││────────────────────────────────────────────────────────────────────│
137 | │io_busy ││ ┌───────────────────┐ ┌───────────────────┐ │
138 | │ ││──────────┘ └─────────┘ └───────│
139 | │ ││──────────────────────────────┬─────────┬───────────────────┬───────│
140 | │read_data ││ 00000000 │0000001E │00000000 │0000001│
141 | │ ││──────────────────────────────┴─────────┴───────────────────┴───────│
142 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}]
143 |
144 | let%expect_test "when ops back to back, will always halt after first one." =
145 | let pattern =
146 | [
147 | (false, false);
148 | (true, false);
149 | (false, false);
150 | (true, false);
151 | (false, false);
152 | (false, false);
153 | (false, false);
154 | ]
155 | in
156 | let waves = testbench pattern in
157 | Waveform.print ~wave_width:4 ~display_width:90 ~display_height:13 waves;
158 | [%expect
159 | {|
160 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐
161 | │clock ││┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
162 | │ ││ └────┘ └────┘ └────┘ └────┘ └────┘ └────┘ └──│
163 | │read_enable ││ ┌─────────┐ ┌─────────┐ │
164 | │ ││──────────┘ └─────────┘ └───────────────────────────│
165 | │write_enable ││ │
166 | │ ││────────────────────────────────────────────────────────────────────│
167 | │io_busy ││ ┌───────────────────┐ │
168 | │ ││──────────┘ └─────────────────────────────────────│
169 | │ ││──────────────────────────────┬─────────┬───────────────────────────│
170 | │read_data ││ 00000000 │0000001E │00000000 │
171 | │ ││──────────────────────────────┴─────────┴───────────────────────────│
172 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}]
173 |
174 | let%expect_test "stalls for correct number of cycles starts with a read, ends \
175 | with a write" =
176 | let pattern =
177 | [
178 | (true, false);
179 | (false, false);
180 | (false, false);
181 | (false, true);
182 | (false, false);
183 | (false, false);
184 | (false, false);
185 | ]
186 | in
187 | let waves = testbench pattern in
188 | Waveform.print ~wave_width:4 ~display_width:90 ~display_height:13 waves;
189 | [%expect
190 | {|
191 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐
192 | │clock ││┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
193 | │ ││ └────┘ └────┘ └────┘ └────┘ └────┘ └────┘ └──│
194 | │read_enable ││──────────┐ │
195 | │ ││ └─────────────────────────────────────────────────────────│
196 | │write_enable ││ ┌─────────┐ │
197 | │ ││──────────────────────────────┘ └───────────────────────────│
198 | │io_busy ││────────────────────┐ ┌─────────────────────────────────────│
199 | │ ││ └─────────┘ │
200 | │ ││────────────────────┬─────────┬─────────────────────────────────────│
201 | │read_data ││ 00000000 │0000001E │00000000 │
202 | │ ││────────────────────┴─────────┴─────────────────────────────────────│
203 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘ |}]
204 |
--------------------------------------------------------------------------------
/lib/instruction_decode/control_unit.ml:
--------------------------------------------------------------------------------
1 | open Hardcaml
2 | open Hardcaml.Signal
3 |
4 | module Instruction_format = struct
5 | let default = of_string "2'h0"
6 |
7 | let r_type = of_string "2'h1"
8 |
9 | let i_type = of_string "2'h2"
10 |
11 | let j_type = of_string "2'h3"
12 | end
13 |
14 | module Instruction_type = struct
15 | let default = of_int ~width:7 0
16 |
17 | (* Arithmetic *)
18 | let add = of_int ~width:7 10
19 |
20 | let addu = of_int ~width:7 11
21 |
22 | let addi = of_int ~width:7 12
23 |
24 | let addiu = of_int ~width:7 13
25 |
26 | let sub = of_int ~width:7 14
27 |
28 | let subu = of_int ~width:7 15
29 |
30 | (* Basic Logical *)
31 | let and_ = of_int ~width:7 20
32 |
33 | let andi = of_int ~width:7 21
34 |
35 | let or_ = of_int ~width:7 22
36 |
37 | let ori = of_int ~width:7 23
38 |
39 | let xor = of_int ~width:7 24
40 |
41 | let xori = of_int ~width:7 25
42 |
43 | (* Shifts *)
44 | let sll = of_int ~width:7 30
45 |
46 | let sllv = of_int ~width:7 31
47 |
48 | let srl = of_int ~width:7 32
49 |
50 | let srlv = of_int ~width:7 33
51 |
52 | let sra = of_int ~width:7 34
53 |
54 | let srav = of_int ~width:7 35
55 |
56 | (* Other I-Type *)
57 | let lui = of_int ~width:7 40
58 |
59 | (* Comparison *)
60 | let slt = of_int ~width:7 50
61 |
62 | let sltu = of_int ~width:7 51
63 |
64 | let slti = of_int ~width:7 52
65 |
66 | let sltiu = of_int ~width:7 53
67 |
68 |
69 | (* Memory *)
70 | let lw = of_int ~width:7 60
71 |
72 | let sw = of_int ~width:7 61
73 |
74 | (* Jump *)
75 |
76 | let j = of_int ~width:7 70
77 |
78 | let jr = of_int ~width:7 71
79 |
80 | let jal = of_int ~width:7 72
81 |
82 | (* Branch *)
83 |
84 | let bne = of_int ~width:7 80
85 |
86 | let beq = of_int ~width:7 81
87 | end
88 |
89 | module Alu_ops = struct
90 | let default = of_int ~width:5 0
91 |
92 | let noop = of_int ~width:5 1
93 |
94 | let add = of_int ~width:5 2
95 |
96 | let addu = of_int ~width:5 3
97 |
98 | let and_ = of_int ~width:5 4
99 |
100 | let lui = of_int ~width:5 5
101 |
102 | let or_ = of_int ~width:5 6
103 |
104 | let slt = of_int ~width:5 7
105 |
106 | let sltu = of_int ~width:5 8
107 |
108 | let sll = of_int ~width:5 9
109 |
110 | let sra = of_int ~width:5 10
111 |
112 | let srl = of_int ~width:5 11
113 |
114 | let sub = of_int ~width:5 12
115 |
116 | let subu = of_int ~width:5 13
117 |
118 | let xor = of_int ~width:5 14
119 | end
120 |
121 | module Pc_sel = struct
122 | module Enum = struct
123 | type t =
124 | | Pc_incr
125 | | Jump_addr
126 | | Jump_reg
127 | | Branch_eq
128 | | Branch_neq
129 | [@@deriving sexp_of, compare, enumerate]
130 | end
131 |
132 | include Interface.Make_enums(Enum)
133 | end
134 |
135 | module Parsed_instruction = struct
136 | type 'a t = {
137 | rs : 'a; [@bits 5]
138 | rt : 'a; [@bits 5]
139 | rdest : 'a; [@bits 5]
140 | shamt : 'a; [@bits 5]
141 | se_imm : 'a; [@bits 32]
142 | alu_imm : 'a; [@bits 32]
143 | addr: 'a; [@bits 26]
144 | }
145 | [@@deriving sexp_of, hardcaml]
146 | end
147 |
148 | module Control_signals = struct
149 | type 'a t = {
150 | reg_write_enable : 'a;
151 | sel_mem_for_reg_data : 'a;
152 | mem_write_enable : 'a;
153 | mem_read_enable : 'a;
154 | sel_shift_for_alu : 'a;
155 | sel_imm_for_alu : 'a;
156 | stall_pc: 'a;
157 | jal: 'a;
158 | alu_control : 'a; [@bits width Alu_ops.default]
159 | pc_sel: 'a Pc_sel.Binary.t;
160 | }
161 | [@@deriving sexp_of, hardcaml]
162 | end
163 |
164 | module I = struct
165 | type 'a t = { instruction : 'a [@bits 32] } [@@deriving sexp_of, hardcaml]
166 | end
167 |
168 | module O = struct
169 | type 'a t = {
170 | parsed_instruction : 'a Parsed_instruction.t;
171 | control_signals : 'a Control_signals.t;
172 | }
173 | [@@deriving sexp_of, hardcaml]
174 | end
175 |
176 | let rtype_classifier instr =
177 | let module T = Instruction_type in
178 | let funct = instr.:[(5, 0)] in
179 | let type_ = Always.Variable.wire ~default:T.default in
180 | Always.(
181 | compile
182 | [
183 | switch funct
184 | [
185 | (of_string "6'b100000", [ type_ <-- T.add ]);
186 | (of_string "6'b100001", [ type_ <-- T.addu ]);
187 | (of_string "6'b100011", [ type_ <-- T.subu ]);
188 | (of_string "6'b100100", [ type_ <-- T.and_ ]);
189 | (of_string "6'b100010", [ type_ <-- T.sub ]);
190 | (of_string "6'b100101", [ type_ <-- T.or_ ]);
191 | (of_string "6'b100110", [ type_ <-- T.xor ]);
192 | (of_string "6'b101010", [ type_ <-- T.slt ]);
193 | (of_string "6'b101011", [ type_ <-- T.sltu ]);
194 | (of_string "6'b000000", [ type_ <-- T.sll ]);
195 | (of_string "6'b000010", [ type_ <-- T.srl ]);
196 | (of_string "6'b000011", [ type_ <-- T.sra ]);
197 | (of_string "6'b000100", [ type_ <-- T.sllv ]);
198 | (of_string "6'b000110", [ type_ <-- T.srlv ]);
199 | (of_string "6'b000111", [ type_ <-- T.srav ]);
200 | (of_string "6'b001000", [ type_ <-- T.jr ]);
201 | ];
202 | ]);
203 | Always.Variable.value type_
204 |
205 | let classifier instr =
206 | let module F = Instruction_format in
207 | let module T = Instruction_type in
208 | let opcode = instr.:[(31, 26)] in
209 | let format = Always.Variable.wire ~default:Instruction_format.default in
210 | let type_ = Always.Variable.wire ~default:Instruction_type.default in
211 | Always.(
212 | compile
213 | [
214 | switch opcode
215 | [
216 | ( of_string "6'b000000",
217 | [ format <-- F.r_type; type_ <-- rtype_classifier instr ] );
218 | (of_string "6'b001000", [ format <-- F.i_type; type_ <-- T.addi ]);
219 | (of_string "6'b001001", [ format <-- F.i_type; type_ <-- T.addiu ]);
220 | (of_string "6'b001100", [ format <-- F.i_type; type_ <-- T.andi ]);
221 | (of_string "6'b001101", [ format <-- F.i_type; type_ <-- T.ori ]);
222 | (of_string "6'b001110", [ format <-- F.i_type; type_ <-- T.xori ]);
223 | (of_string "6'b001111", [ format <-- F.i_type; type_ <-- T.lui ]);
224 | (of_string "6'b001010", [ format <-- F.i_type; type_ <-- T.slti ]);
225 | (of_string "6'b001011", [ format <-- F.i_type; type_ <-- T.sltiu ]);
226 | (of_string "6'b100011", [ format <-- F.i_type; type_ <-- T.lw ]);
227 | (of_string "6'b101011", [ format <-- F.i_type; type_ <-- T.sw ]);
228 | (of_string "6'b000010", [ format <-- F.j_type; type_ <-- T.j]);
229 | (of_string "6'b000011", [ format <-- F.j_type; type_ <-- T.jal]);
230 | (of_string "6'b000101", [ format <-- F.j_type; type_ <-- T.bne]);
231 | (of_string "6'b000100", [ format <-- F.j_type; type_ <-- T.beq]);
232 |
233 | ];
234 | ]);
235 | (Always.Variable.value format, Always.Variable.value type_)
236 |
237 |
238 | let parser instr format type_ =
239 | let rt = instr.:[(20, 16)] in
240 | let rd = instr.:[(15, 11)] in
241 | let rdest = priority_select_with_default ~default:rd
242 | [
243 | {
244 | With_valid.valid = type_ ==: Instruction_type.jal;
245 | value = of_string "5'd31";
246 | };
247 | {
248 | With_valid.valid = format ==: Instruction_format.i_type;
249 | value = rt;
250 | };
251 | ] in
252 | let ze_imm = uresize instr.:[(15, 0)] 32 in
253 | let se_imm = sresize instr.:[(15, 0)] 32 in
254 | let use_ze_for_imm =
255 | type_ ==: Instruction_type.addiu
256 | |: (type_ ==: Instruction_type.sltiu)
257 | |: (type_ ==: Instruction_type.lw)
258 | |: (type_ ==: Instruction_type.sw)
259 | |: (type_ ==: Instruction_type.andi)
260 | |: (type_ ==: Instruction_type.ori)
261 | |: (type_ ==: Instruction_type.xori)
262 | |: (type_ ==: Instruction_type.sll)
263 | |: (type_ ==: Instruction_type.srl)
264 | |: (type_ ==: Instruction_type.sra)
265 | in
266 | let alu_imm = mux2 use_ze_for_imm ze_imm se_imm in
267 | let module P = Parsed_instruction in
268 | {
269 | P.rs = instr.:[(25, 21)];
270 | rt;
271 | rdest;
272 | shamt = instr.:[(10, 6)];
273 | se_imm;
274 | alu_imm;
275 | addr = instr.:[(25, 0)];
276 | }
277 |
278 | let type_to_alu_control type_ =
279 | let module O = Alu_ops in
280 | let module T = Instruction_type in
281 | let aluc = Always.Variable.wire ~default:Alu_ops.default in
282 | Always.(
283 | compile
284 | [
285 | switch type_
286 | [
287 | (* Arithmetic *)
288 | (T.add, [ aluc <-- O.add ]);
289 | (T.addu, [ aluc <-- O.addu ]);
290 | (T.addi, [ aluc <-- O.addu ]);
291 | (T.addiu, [ aluc <-- O.addu ]);
292 | (T.sub, [ aluc <-- O.sub ]);
293 | (T.subu, [ aluc <-- O.subu ]);
294 | (* Basic Logical *)
295 | (T.and_, [ aluc <-- O.and_ ]);
296 | (T.andi, [ aluc <-- O.and_ ]);
297 | (T.or_, [ aluc <-- O.or_ ]);
298 | (T.ori, [ aluc <-- O.or_ ]);
299 | (T.xor, [ aluc <-- O.xor ]);
300 | (T.xori, [ aluc <-- O.xor ]);
301 | (* Shifts *)
302 | (T.sll, [ aluc <-- O.sll ]);
303 | (T.sllv, [ aluc <-- O.sll ]);
304 | (T.sra, [ aluc <-- O.sra ]);
305 | (T.srav, [ aluc <-- O.sra ]);
306 | (T.srl, [ aluc <-- O.srl ]);
307 | (T.srlv, [ aluc <-- O.srl ]);
308 | (* Other I-Type *)
309 | (T.lui, [ aluc <-- O.lui ]);
310 | (* Comparison *)
311 | (T.slt, [ aluc <-- O.slt ]);
312 | (T.sltu, [ aluc <-- O.sltu ]);
313 | (T.slti, [ aluc <-- O.slt ]);
314 | (T.sltiu, [ aluc <-- O.sltu ]);
315 | (* Memory *)
316 | (T.lw, [ aluc <-- O.add ]);
317 | (T.sw, [ aluc <-- O.add ]);
318 | (* Jump *)
319 | (T.j, [ aluc <-- O.noop ]);
320 | (T.jal, [ aluc <-- O.noop ]);
321 | (T.jr, [ aluc <-- O.noop ]);
322 | (* Branch *)
323 | (T.bne, [ aluc <-- O.noop ]);
324 | (T.beq, [ aluc <-- O.noop ]);
325 | ];
326 | ]);
327 | Always.Variable.value aluc
328 |
329 | let type_to_pc_sel type_ =
330 | let module PE = Pc_sel.Enum in
331 | let module PB = Pc_sel.Binary in
332 | let of_enum = PB.of_enum (module Signal) in
333 | PB.Of_signal.priority_select_with_default ~default:(of_enum PE.Pc_incr)
334 | [
335 | {
336 | With_valid.valid = (type_ ==: Instruction_type.j )|: (type_ ==: Instruction_type.jal);
337 | value = of_enum PE.Jump_addr;
338 | };
339 | {
340 | With_valid.valid = type_ ==: Instruction_type.jr;
341 | value = of_enum PE.Jump_reg;
342 | };
343 | {
344 | With_valid.valid = type_ ==: Instruction_type.beq;
345 | value = of_enum PE.Branch_eq;
346 | };
347 | {
348 | With_valid.valid = type_ ==: Instruction_type.bne;
349 | value = of_enum PE.Branch_neq;
350 | };
351 | ]
352 |
353 | let control_core format type_ =
354 | let module F = Instruction_format in
355 | let module T = Instruction_type in
356 | let reg_write_enable =
357 | ((format ==: F.r_type) &: (type_ <>: T.jr)) |: (type_ ==: T.addi) |: (type_ ==: T.addiu)
358 | |: (type_ ==: T.andi) |: (type_ ==: T.ori) |: (type_ ==: T.xori)
359 | |: (type_ ==: T.lui) |: (type_ ==: T.slti) |: (type_ ==: T.sltiu)
360 | |: (type_ ==: T.lw) |: (type_ ==: T.jal)
361 | in
362 | let sel_mem_for_reg_data = type_ ==: T.lw in
363 | let mem_write_enable = type_ ==: T.sw in
364 | let mem_read_enable = type_ ==: T.lw in
365 | let sel_shift_for_alu =
366 | type_ ==: T.sll |: (type_ ==: T.srl) |: (type_ ==: T.sra)
367 | in
368 | let sel_imm_for_alu = format ==: F.i_type in
369 | let alu_control = type_to_alu_control type_ in
370 | let pc_sel = type_to_pc_sel type_ in
371 | let jal = type_ ==: T.jal in
372 | let module C = Control_signals in
373 | {
374 | C.reg_write_enable;
375 | sel_mem_for_reg_data;
376 | mem_write_enable;
377 | mem_read_enable;
378 | sel_shift_for_alu;
379 | sel_imm_for_alu;
380 | alu_control;
381 | (* This will get overriden in `instruction_decode` *)
382 | stall_pc = of_string "1'b0";
383 | pc_sel;
384 | jal;
385 | }
386 |
387 | let circuit_impl (_scope : Scope.t) (input : _ I.t) =
388 | let instr_format, type_ = classifier input.instruction in
389 | let parsed_instruction = parser input.instruction instr_format type_ in
390 | let control_signals = control_core instr_format type_ in
391 | { O.parsed_instruction; control_signals }
392 |
393 | let circuit_impl_exn scope input =
394 | let module W = Width_check.With_interface (I) (O) in
395 | W.check_widths (circuit_impl scope) input
396 |
397 | let hierarchical scope input =
398 | let module H = Hierarchy.In_scope (I) (O) in
399 | H.hierarchical ~scope ~name:"control_unit" circuit_impl_exn input
400 |
--------------------------------------------------------------------------------
/arty/boards/arty-a7-35/E.0/preset.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
--------------------------------------------------------------------------------
/test/instruction_decode/test_instruction_decode.ml:
--------------------------------------------------------------------------------
1 | open! Base
2 | open Hardcaml
3 | open Hardcaml_waveterm
4 | open Mips.Instruction_decode
5 | module Simulator = Cyclesim.With_interface (I) (O)
6 |
7 | type test_input = {
8 | instruction : string;
9 | write_enable : string;
10 | write_address : string;
11 | write_data : string;
12 | }
13 |
14 | let testbench tests =
15 | let scope = Scope.create ~flatten_design:true () in
16 | let sim = Simulator.create (circuit_impl_exn scope) in
17 | let waves, sim = Waveform.create sim in
18 | let inputs = Cyclesim.inputs sim in
19 |
20 | let step ~test =
21 | inputs.enable_pipeline := Bits.of_bool true;
22 | inputs.instruction := Bits.of_string test.instruction;
23 | inputs.writeback_reg_write_enable := Bits.of_string test.write_enable;
24 | inputs.writeback_address := Bits.of_string test.write_address;
25 | inputs.writeback_data := Bits.of_string test.write_data;
26 | Cyclesim.cycle sim
27 | in
28 |
29 | List.iter tests ~f:(fun test -> step ~test);
30 |
31 | waves
32 |
33 | let%expect_test "can we read and write to/from reg file properly" =
34 | let add_rs_9_rt_8_rd_10 = "32'h01285020" in
35 | let tests =
36 | [
37 | (* First, check that write_enable=0 doesn't write, and that initially reads 0 *)
38 | {
39 | instruction = add_rs_9_rt_8_rd_10;
40 | write_enable = "1'h0";
41 | write_address = "5'h9";
42 | write_data = "32'h7";
43 | };
44 | (* alu_a should now be 6 after this step *)
45 | {
46 | instruction = add_rs_9_rt_8_rd_10;
47 | write_enable = "1'h1";
48 | write_address = "5'h9";
49 | write_data = "32'h6";
50 | };
51 | (* Another test that write_enable=0 works as intended *)
52 | {
53 | instruction = add_rs_9_rt_8_rd_10;
54 | write_enable = "1'h0";
55 | write_address = "5'h8";
56 | write_data = "32'h20";
57 | };
58 | (* After this step, both alu_a and alu_b should have values: 6 and 21 respectively *)
59 | {
60 | instruction = add_rs_9_rt_8_rd_10;
61 | write_enable = "1'h1";
62 | write_address = "5'h8";
63 | write_data = "32'h21";
64 | };
65 | (* One more for good measure *)
66 | {
67 | instruction = add_rs_9_rt_8_rd_10;
68 | write_enable = "1'h0";
69 | write_address = "5'h0";
70 | write_data = "32'h0";
71 | };
72 | ]
73 | in
74 | let waves = testbench tests in
75 | Waveform.expect ~show_digest:true ~wave_width:4 ~display_width:90
76 | ~display_height:68 waves;
77 | [%expect
78 | {|
79 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐
80 | │clock ││┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
81 | │ ││ └────┘ └────┘ └────┘ └────┘ └────┘ └────┘ └──│
82 | │ ││────────────────────────────────────────────────── │
83 | │e_alu_output ││ 00000000 │
84 | │ ││────────────────────────────────────────────────── │
85 | │enable_pipeline ││────────────────────────────────────────────────── │
86 | │ ││ │
87 | │ ││────────────────────────────────────────────────── │
88 | │instruction ││ 01285020 │
89 | │ ││────────────────────────────────────────────────── │
90 | │ ││────────────────────────────────────────────────── │
91 | │m_alu_output ││ 00000000 │
92 | │ ││────────────────────────────────────────────────── │
93 | │ ││────────────────────────────────────────────────── │
94 | │m_data_output ││ 00000000 │
95 | │ ││────────────────────────────────────────────────── │
96 | │ ││────────────────────┬───────────────────┬───────── │
97 | │writeback_address ││ 09 │08 │00 │
98 | │ ││────────────────────┴───────────────────┴───────── │
99 | │ ││──────────┬─────────┬─────────┬─────────┬───────── │
100 | │writeback_data ││ 00000007 │00000006 │00000020 │00000021 │00000000 │
101 | │ ││──────────┴─────────┴─────────┴─────────┴───────── │
102 | │writeback_reg_writ││ ┌─────────┐ ┌─────────┐ │
103 | │ ││──────────┘ └─────────┘ └───────── │
104 | │ ││────────────────────────────────────────────────── │
105 | │addr ││ 1285020 │
106 | │ ││────────────────────────────────────────────────── │
107 | │ ││──────────┬─────────────────────────────────────── │
108 | │alu_a ││ 00000000 │00000006 │
109 | │ ││──────────┴─────────────────────────────────────── │
110 | │ ││──────────────────────────────┬─────────────────── │
111 | │alu_b ││ 00000000 │00000021 │
112 | │ ││──────────────────────────────┴─────────────────── │
113 | │ ││────────────────────────────────────────────────── │
114 | │alu_control ││ 02 │
115 | │ ││────────────────────────────────────────────────── │
116 | │ ││────────────────────────────────────────────────── │
117 | │alu_imm ││ 00005020 │
118 | │ ││────────────────────────────────────────────────── │
119 | │ ││────────────────────────────────────────────────── │
120 | │binary_variant ││ 0 │
121 | │ ││────────────────────────────────────────────────── │
122 | │jal ││ │
123 | │ ││────────────────────────────────────────────────── │
124 | │mem_read_enable ││ │
125 | │ ││────────────────────────────────────────────────── │
126 | │mem_write_enable ││ │
127 | │ ││────────────────────────────────────────────────── │
128 | │ ││────────────────────────────────────────────────── │
129 | │rdest ││ 0A │
130 | │ ││────────────────────────────────────────────────── │
131 | │reg_write_enable ││────────────────────────────────────────────────── │
132 | │ ││ │
133 | │ ││────────────────────────────────────────────────── │
134 | │se_imm ││ 00005020 │
135 | │ ││────────────────────────────────────────────────── │
136 | │sel_imm_for_alu ││ │
137 | │ ││────────────────────────────────────────────────── │
138 | │sel_mem_for_reg_da││ │
139 | │ ││────────────────────────────────────────────────── │
140 | │sel_shift_for_alu ││ │
141 | │ ││────────────────────────────────────────────────── │
142 | │stall_pc ││ │
143 | │ ││────────────────────────────────────────────────── │
144 | │ ││ │
145 | │ ││ │
146 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘
147 | b8927b78dd2fad3be72c95e9789ed5b9 |}]
148 |
149 | let%expect_test "0 register always returns 0, regardless of actual contents" =
150 | let add_rs_9_rt_0_rd_8 = "32'h01204020" in
151 | let tests =
152 | [
153 | (* First, write to the 0 register. rt should still be 0 after this. *)
154 | {
155 | instruction = add_rs_9_rt_0_rd_8;
156 | write_enable = "1'h1";
157 | write_address = "5'h0";
158 | write_data = "32'h7";
159 | };
160 | (* Next, write to register 8. rs should be 7 after this. *)
161 | {
162 | instruction = add_rs_9_rt_0_rd_8;
163 | write_enable = "1'h1";
164 | write_address = "5'h9";
165 | write_data = "32'h7";
166 | };
167 | {
168 | instruction = add_rs_9_rt_0_rd_8;
169 | write_enable = "1'h0";
170 | write_address = "5'h0";
171 | write_data = "32'h7";
172 | };
173 | ]
174 | in
175 | let waves = testbench tests in
176 | Waveform.expect ~show_digest:true ~wave_width:4 ~display_width:90
177 | ~display_height:68 waves;
178 | [%expect
179 | {|
180 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────┐
181 | │clock ││┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
182 | │ ││ └────┘ └────┘ └────┘ └────┘ └────┘ └────┘ └──│
183 | │ ││────────────────────────────── │
184 | │e_alu_output ││ 00000000 │
185 | │ ││────────────────────────────── │
186 | │enable_pipeline ││────────────────────────────── │
187 | │ ││ │
188 | │ ││────────────────────────────── │
189 | │instruction ││ 01204020 │
190 | │ ││────────────────────────────── │
191 | │ ││────────────────────────────── │
192 | │m_alu_output ││ 00000000 │
193 | │ ││────────────────────────────── │
194 | │ ││────────────────────────────── │
195 | │m_data_output ││ 00000000 │
196 | │ ││────────────────────────────── │
197 | │ ││──────────┬─────────┬───────── │
198 | │writeback_address ││ 00 │09 │00 │
199 | │ ││──────────┴─────────┴───────── │
200 | │ ││────────────────────────────── │
201 | │writeback_data ││ 00000007 │
202 | │ ││────────────────────────────── │
203 | │writeback_reg_writ││────────────────────┐ │
204 | │ ││ └───────── │
205 | │ ││────────────────────────────── │
206 | │addr ││ 1204020 │
207 | │ ││────────────────────────────── │
208 | │ ││──────────┬─────────────────── │
209 | │alu_a ││ 00000000 │00000007 │
210 | │ ││──────────┴─────────────────── │
211 | │ ││────────────────────────────── │
212 | │alu_b ││ 00000000 │
213 | │ ││────────────────────────────── │
214 | │ ││────────────────────────────── │
215 | │alu_control ││ 02 │
216 | │ ││────────────────────────────── │
217 | │ ││────────────────────────────── │
218 | │alu_imm ││ 00004020 │
219 | │ ││────────────────────────────── │
220 | │ ││────────────────────────────── │
221 | │binary_variant ││ 0 │
222 | │ ││────────────────────────────── │
223 | │jal ││ │
224 | │ ││────────────────────────────── │
225 | │mem_read_enable ││ │
226 | │ ││────────────────────────────── │
227 | │mem_write_enable ││ │
228 | │ ││────────────────────────────── │
229 | │ ││────────────────────────────── │
230 | │rdest ││ 08 │
231 | │ ││────────────────────────────── │
232 | │reg_write_enable ││────────────────────────────── │
233 | │ ││ │
234 | │ ││────────────────────────────── │
235 | │se_imm ││ 00004020 │
236 | │ ││────────────────────────────── │
237 | │sel_imm_for_alu ││ │
238 | │ ││────────────────────────────── │
239 | │sel_mem_for_reg_da││ │
240 | │ ││────────────────────────────── │
241 | │sel_shift_for_alu ││ │
242 | │ ││────────────────────────────── │
243 | │stall_pc ││ │
244 | │ ││────────────────────────────── │
245 | │ ││ │
246 | │ ││ │
247 | └──────────────────┘└────────────────────────────────────────────────────────────────────┘
248 | d6d577b829d8e9bf8f327c83d9c64474 |}]
249 |
250 | let%expect_test "Stalls when appropriate" =
251 | let add_rs_9_rt_0_rd_8 = "32'h01204020" in
252 | let lw_into_9 = "32'h8D090000" in
253 | let lw_into_8 = "32'h8C080000" in
254 | let sw_from_8 = "32'hAD0D0000" in
255 | let sw_from_9 = "32'hAD2D0000" in
256 |
257 | let no_write =
258 | {
259 | instruction = "INVALID";
260 | write_enable = "1'b0";
261 | write_address = "5'h0";
262 | write_data = "32'h0";
263 | }
264 | in
265 |
266 | let tests =
267 | [
268 | (* Should stall here *)
269 | { no_write with instruction = lw_into_9 };
270 | { no_write with instruction = add_rs_9_rt_0_rd_8 };
271 | (* Shouldn't stall on the first two as no register overlap *)
272 | { no_write with instruction = lw_into_8 };
273 | { no_write with instruction = add_rs_9_rt_0_rd_8 };
274 | (* Should stall again, but this time mem write should be affected *)
275 | { no_write with instruction = lw_into_9 };
276 | { no_write with instruction = sw_from_9 };
277 | (* Shouldn't stall here either, same reason. *)
278 | { no_write with instruction = lw_into_9 };
279 | { no_write with instruction = sw_from_8 };
280 | ]
281 | in
282 | let waves = testbench tests in
283 |
284 | let display_rules =
285 | [
286 | Display_rule.port_name_is_one_of
287 | [ "stall_pc"; "mem_write_enable"; "reg_write_enable" ]
288 | ~wave_format:Wave_format.Bit;
289 | ]
290 | in
291 | Waveform.expect ~display_rules ~show_digest:true ~wave_width:4
292 | ~display_width:130 ~display_height:10 waves;
293 | [%expect
294 | {|
295 | ┌Signals───────────┐┌Waves───────────────────────────────────────────────────────────────────────────────────────────────────────┐
296 | │mem_write_enable ││ ┌───────── │
297 | │ ││──────────────────────────────────────────────────────────────────────┘ │
298 | │reg_write_enable ││──────────┐ ┌─────────────────────────────┐ ┌─────────┐ │
299 | │ ││ └─────────┘ └─────────┘ └───────── │
300 | │stall_pc ││ ┌─────────┐ ┌─────────┐ │
301 | │ ││──────────┘ └─────────────────────────────┘ └─────────────────── │
302 | │ ││ │
303 | │ ││ │
304 | └──────────────────┘└────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
305 | 0c7d7f198064acf7ecb50adff2647c62 |}]
306 |
--------------------------------------------------------------------------------