├── doc ├── designNotes.pdf ├── src │ └── designNotes.tex └── README.md ├── .gitignore ├── syn ├── de1_quartus2 │ ├── constraints.sdc │ ├── makefile │ └── build.tcl └── zybo_vivado │ ├── README.txt │ ├── makefile │ └── build.tcl ├── src ├── sw │ ├── hello │ │ ├── makefile │ │ ├── obj_code_pkg.vhdl │ │ └── hello.mac │ ├── diagnostic │ │ └── makefile │ └── common │ │ └── common.mk ├── vhdl │ ├── rtl │ │ ├── mcu │ │ │ ├── mcu80_pkg.vhdl │ │ │ ├── mcu80_irq.vhdl │ │ │ ├── mcu80.vhdl │ │ │ └── mcu80_uart.vhdl │ │ └── light8080_ucode_pkg.vhdl │ └── testbench │ │ ├── light8080_tb_pkg.vhdl │ │ ├── mcu80_tb.vhdl │ │ └── txt_util.vhdl └── ucode │ └── light8080.m80 ├── boards ├── zybo │ ├── constraints │ │ └── vivado-zybo.xdc │ └── zybo_top.vhdl └── de1 │ └── de1_top.vhdl ├── tools ├── Makefile.asl.def ├── build_rom │ ├── templates │ │ └── template.vhdl │ └── src │ │ └── build_rom.py └── Makefile └── README.md /doc/designNotes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaruiz/light8080/HEAD/doc/designNotes.pdf -------------------------------------------------------------------------------- /doc/src/designNotes.tex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaruiz/light8080/HEAD/doc/src/designNotes.tex -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .local 2 | local 3 | syn/**/output/* 4 | sim/**/*.o 5 | sim/**/*.lst 6 | sim/**/*.cf 7 | sim/ghdl/* 8 | ~sim/ghdl/makefile 9 | ~sim/ghdl/README.* 10 | src/sw/**/*.ihx 11 | src/sw/**/*.lst 12 | src/sw/**/*.p 13 | tools/asl/* 14 | -------------------------------------------------------------------------------- /doc/README.md: -------------------------------------------------------------------------------- 1 | This directory only contains the old (2007) original design notes. 2 | Both the LaTeX source and the resulting PDF are included, although no makefile or script is supplied to produce the latter. 3 | 4 | Eventually this will be replaced with some sort of mini-user-guide. 5 | -------------------------------------------------------------------------------- /syn/de1_quartus2/constraints.sdc: -------------------------------------------------------------------------------- 1 | # Constrain clock port clk with a 20ns requirement 2 | create_clock -period 20 [get_ports clk_50MHz] 3 | 4 | # Automatically apply a generate clock on the output of phase-locked loops (PLLs) 5 | # This command can be safely left in the SDC even if no PLLs exist in the design 6 | 7 | derive_pll_clocks -------------------------------------------------------------------------------- /src/sw/hello/makefile: -------------------------------------------------------------------------------- 1 | #-- See main makefile at ../common/common.mk 2 | 3 | #-- Project configuration ------------------------------------------------------ 4 | 5 | # SW build parameters. 6 | PROJ_NAME = hello 7 | 8 | # HW configuration. Will be passed on to TB as generics/parameters. 9 | # (None of that here.) 10 | 11 | # Include the main makefile body with all the rules. 12 | include ../common/common.mk 13 | -------------------------------------------------------------------------------- /src/sw/diagnostic/makefile: -------------------------------------------------------------------------------- 1 | #-- See main makefile at ../common/common.mk 2 | 3 | #-- Project configuration ------------------------------------------------------ 4 | 5 | # Project name as used in generated code. 6 | PROJ_NAME = diagnostic 7 | 8 | #-- HW configuration. Will be passed on to TB as generics/parameters ----------- 9 | # (None of that here.) 10 | 11 | # Include the main makefile body with all the rules. 12 | include ../common/common.mk 13 | -------------------------------------------------------------------------------- /boards/zybo/constraints/vivado-zybo.xdc: -------------------------------------------------------------------------------- 1 | create_clock -period 8 [get_ports clk_125MHz_i] 2 | 3 | set_property PACKAGE_PIN T16 [get_ports {switches_i[3]}] 4 | set_property PACKAGE_PIN W13 [get_ports {switches_i[2]}] 5 | set_property PACKAGE_PIN P15 [get_ports {switches_i[1]}] 6 | set_property PACKAGE_PIN G15 [get_ports {switches_i[0]}] 7 | 8 | set_property PACKAGE_PIN Y16 [get_ports {buttons_i[3]}] 9 | set_property PACKAGE_PIN V16 [get_ports {buttons_i[2]}] 10 | set_property PACKAGE_PIN P16 [get_ports {buttons_i[1]}] 11 | set_property PACKAGE_PIN R18 [get_ports {buttons_i[0]}] 12 | 13 | set_property PACKAGE_PIN D18 [get_ports {leds_o[3]}] 14 | set_property PACKAGE_PIN G14 [get_ports {leds_o[2]}] 15 | set_property PACKAGE_PIN M15 [get_ports {leds_o[1]}] 16 | set_property PACKAGE_PIN M14 [get_ports {leds_o[0]}] 17 | 18 | set_property PACKAGE_PIN L16 [get_ports clk_125MHz_i] 19 | 20 | set_property PACKAGE_PIN W16 [get_ports pmod_e_2_txd_o] 21 | set_property PACKAGE_PIN J15 [get_ports pmod_e_3_rxd_i] 22 | 23 | # IO standard set by default. 24 | # Set individually other pins that need a different standard. 25 | set_property IOSTANDARD LVCMOS33 [get_ports *] 26 | 27 | 28 | -------------------------------------------------------------------------------- /tools/Makefile.asl.def: -------------------------------------------------------------------------------- 1 | # This makefile fragment contains build options for the ASL assembler. 2 | # By default, ASL install dir will be under the current dir; this is the 3 | # default path assumed by light8080 makefiles. 4 | # 5 | # ------------------------------------------------------------------------- 6 | # choose your compiler (must be ANSI-compliant!) and linker command, plus 7 | # any additionally needed flags 8 | 9 | CC = gcc 10 | LD = gcc 11 | CFLAGS = -O3 -fomit-frame-pointer -Wall 12 | LDFLAGS = 13 | 14 | TARG_OBJEXTENSION = .o 15 | TARG_EXEXTENSION = 16 | 17 | HOST_OBJEXTENSION = $(TARG_OBJEXTENSION) 18 | HOST_EXEXTENSION = $(TARG_EXEXTENSION) 19 | 20 | # ------------------------------------------------------------------------- 21 | # directories where binaries, includes, and manpages should go during 22 | # installation 23 | 24 | BINDIR = $(CURDIR)/install/bin 25 | INCDIR = $(CURDIR)/install/include/asl 26 | MANDIR = $(CURDIR)/install/man 27 | LIBDIR = $(CURDIR)/install/lib/asl 28 | DOCDIR = $(CURDIR)/install/doc/asl 29 | 30 | # ------------------------------------------------------------------------- 31 | # character encoding to use (choose one of them) 32 | 33 | # CHARSET = CHARSET_ASCII7 34 | # CHARSET = CHARSET_IBM437 35 | # CHARSET = CHARSET_UTF8 36 | CHARSET = CHARSET_ISO8859_1 37 | -------------------------------------------------------------------------------- /tools/build_rom/templates/template.vhdl: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- obj_code_pkg.vhdl -- Application object code in vhdl constant string format. 3 | -------------------------------------------------------------------------------- 4 | -- Written by build_rom.py for project '@project_name@'. 5 | -------------------------------------------------------------------------------- 6 | -- 7 | -- This source file may be used and distributed without 8 | -- restriction provided that this copyright statement is not 9 | -- removed from the file and that any derivative work contains 10 | -- the original copyright notice and the associated disclaimer. 11 | -- 12 | -- This source file is free software; you can redistribute it 13 | -- and/or modify it under the terms of the GNU Lesser General 14 | -- Public License as published by the Free Software Foundation; 15 | -- either version 2.1 of the License, or (at your option) any 16 | -- later version. 17 | -- 18 | -- This source is distributed in the hope that it will be 19 | -- useful, but WITHOUT ANY WARRANTY; without even the implied 20 | -- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 21 | -- PURPOSE. See the GNU Lesser General Public License for more 22 | -- details. 23 | -- 24 | -- You should have received a copy of the GNU Lesser General 25 | -- Public License along with this source; if not, download it 26 | -- from http://www.opencores.org/lgpl.shtml 27 | -------------------------------------------------------------------------------- 28 | 29 | library ieee; 30 | use ieee.std_logic_1164.all; 31 | use ieee.numeric_std.all; 32 | 33 | -- Package with utility functions for handling SoC object code. 34 | use work.mcu80_pkg.all; 35 | 36 | package @obj_pkg_name@ is 37 | 38 | -- Object code initialization constant. 39 | constant object_code : obj_code_t(@bottom_addr@ to @top_addr@) := ( 40 | @obj_bytes@ 41 | ); 42 | 43 | 44 | end package @obj_pkg_name@; 45 | -------------------------------------------------------------------------------- /tools/Makefile: -------------------------------------------------------------------------------- 1 | # ============================================================================== 2 | # Installation of tools required to build the test SW in project light8080. 3 | # This makefile will pull & build whatever is required to build our test SW: 4 | # 5 | # ASL assembler (https://github.com/begoon/asl.git) 6 | # 7 | # This makefile can be considered as sort of 'executable instructions' for you 8 | # to reproduce my setup so you can use the light8080 makefiles unmodified if 9 | # you don't want to tinker with them. 10 | # You'll need git, gcc, etc. and resolving those dependencies is up to you. 11 | # 12 | # TARGETS: 13 | # ========= 14 | # install - Install & build whatever. 15 | # uninstall - Remove anything that was installed, leave dir in reset state. 16 | # 17 | # ============================================================================== 18 | 19 | # Use bash for shell commands like echo. 20 | SHELL := /bin/bash 21 | 22 | .PHONY: clean install uninstall pull_assembler install_assembler \ 23 | check_dependencies 24 | 25 | # Github path for ASL assembler project. 26 | ASL_REPO_PATH = https://github.com/begoon/asl.git 27 | # Will be nonempty if git command is available. 28 | GIT_INSTALLED := $(shell command -v git 2> /dev/null) 29 | 30 | 31 | .DEFAULT: help 32 | .PHONY: help 33 | help: 34 | @echo "Use this makefile to install the ASL assembler locally." 35 | @echo 36 | @echo "GOALS:" 37 | @echo " install - Install & build ASL locally within this directory" 38 | @echo " uninstall - Remove anything that was installed" 39 | @echo 40 | @echo "You'll need git and gcc to installl the tool(s)." 41 | @echo 42 | 43 | 44 | check_dependencies: 45 | ifndef GIT_INSTALLED 46 | $(error "git is not available, please install it.") 47 | endif 48 | 49 | 50 | asl/install/bin/asl: install_assembler 51 | @echo -e "\e[1;33mOk, asl assembler installed at $(CURDIR)/asl/install/bin\e[0m" 52 | 53 | pull_assembler: 54 | ifeq ("$(wildcard asl/INSTALL)","") 55 | @echo -e "\e[1;33mPulling asl assembler sources from Github...\e[0m" 56 | git clone $(ASL_REPO_PATH) 57 | endif 58 | 59 | install_assembler: pull_assembler 60 | @echo -e "\e[1;33mBuilding and installing asl assembler...\e[0m" 61 | @cp Makefile.asl.def asl/Makefile.def 62 | make -C asl 63 | make -C asl install 64 | 65 | install: check_dependencies asl/install/bin/asl 66 | 67 | all: install 68 | 69 | clean: 70 | @make -C asl clean 71 | 72 | uninstall: clean 73 | rm -rf asl 74 | -------------------------------------------------------------------------------- /syn/zybo_vivado/README.txt: -------------------------------------------------------------------------------- 1 | Build makefile -- light8080 demo on Digilent's ZYBO board using Vivado. 2 | 3 | This script will build the project bit stream file using Vivado's non-project 4 | flow mode. The only step not covered in the script is loading the bit stream on 5 | the target board itself. 6 | 7 | The script is meant to be used through the makefile. 8 | 9 | Script `build.tcl` has been mostly copied from the example in page 11 of the 10 | Vivado Tcl scripting guide (ug894, 'Using Tcl Scripting'). 11 | 12 | Output files, including the bit stream, can be found in `./output/zybo_demo`. 13 | 14 | 15 | USAGE 16 | ----- 17 | 18 | make help will display a short list of goals. 19 | make all will launch the synthesis flow. 20 | make clean will clean the directory. 21 | 22 | 23 | XILINX ENVIRONMENT VARIABLES 24 | ---------------------------- 25 | 26 | You need to set up the Xilinx variables before invoking the makefile. 27 | In a regular Linux install this can be done by running this script: 28 | 29 | /opt/Xilinx/Vivado/*/settings64.sh 30 | 31 | Regular users of Vivado won't need this information and casual users need more 32 | than I can supply here. But that hint should get you on the right path. 33 | 34 | 35 | FILES 36 | ----- 37 | 38 | build.tcl -- Run synth and implementation, create bitstream file. 39 | makefile -- Interface to the build script. 40 | README.txt -- This file. 41 | 42 | 43 | TARGET 44 | ------ 45 | 46 | Script build.tcl contains a list of source files and constraint file(s). 47 | All the target HW dependencies (ZYBO board) are contained in the constraints 48 | file. 49 | This script is meant to be generic apart form the file lists and arguments 50 | defined at the beginning. It's just a stock Xilinx script. 51 | 52 | 53 | BUILD 8080 CODE BEFORE SYNTHESIS 54 | -------------------------------- 55 | 56 | The build needs a vhdl package to initialize the 8080 code memory. Script 57 | build.tcl defines a variable `OBJ_CODE_DIR` that should point to a directory 58 | containing such a package. 59 | The scripts uses the diagnostic SW sample by default; you need to edit the 60 | script manually to use any other piece of 8080 software, provided you built the 61 | package for it. 62 | The SW samples in this project can be used as examples. 63 | 64 | 65 | COMPATIBILITY 66 | ------------- 67 | 68 | This has been tested with Vivado 2015.4 and 2017.4 running on a Linux machine. 69 | 70 | It should be possible to run this mini-flow unmodified on Windows but I can't 71 | verify that myself. 72 | -------------------------------------------------------------------------------- /boards/zybo/zybo_top.vhdl: -------------------------------------------------------------------------------- 1 | -- 2 | -- 3 | -- 4 | 5 | library ieee; 6 | use ieee.std_logic_1164.all; 7 | use ieee.numeric_std.all; 8 | 9 | -- Package that contains the program object code in VHDL constant format. 10 | use work.obj_code_pkg.all; 11 | 12 | entity ZYBO_TOP is 13 | port( 14 | -- Clock from Ethernet PHY. @note1. 15 | clk_125MHz_i : in std_logic; 16 | 17 | -- Pushbuttons. 18 | buttons_i : in std_logic_vector(3 downto 0); 19 | -- Switches. 20 | switches_i : in std_logic_vector(3 downto 0); 21 | -- LEDs. 22 | leds_o : out std_logic_vector(3 downto 0); 23 | -- PMOD E (Std) connector -- PMOD UART (Digilent). 24 | pmod_e_2_txd_o : out std_logic; 25 | pmod_e_3_rxd_i : in std_logic 26 | ); 27 | end entity ZYBO_TOP; 28 | 29 | architecture rtl of ZYBO_TOP is 30 | 31 | signal clk : std_logic; 32 | signal reset : std_logic; 33 | 34 | signal extint : std_logic_vector(3 downto 0); 35 | signal iop1 : std_logic_vector(7 downto 0); 36 | signal iop2 : std_logic_vector(7 downto 0); 37 | 38 | 39 | begin 40 | 41 | clk <= clk_125MHz_i; 42 | reset <= buttons_i(3); 43 | 44 | 45 | -- Light8080 MCU and glue logic ---------------------------------------------- 46 | 47 | mcu: entity work.mcu80 48 | generic map ( 49 | OBJ_CODE => work.obj_code_pkg.object_code, 50 | UART_HARDWIRED => false, -- UART baud rate NOT run-time programmable. 51 | UART_IRQ_LINE => 3, -- UART uses IRQ3 line of irq controller. 52 | BAUD_RATE => 115200, -- UART baud rate. 53 | CLOCK_FREQ => 125E6 -- Clock frequency in Hz. 54 | ) 55 | port map ( 56 | clk => clk, 57 | reset => reset, 58 | 59 | p1_i => iop1, 60 | p2_o => iop2, 61 | 62 | extint_i => extint, 63 | 64 | txd_o => pmod_e_2_txd_o, 65 | rxd_i => pmod_e_3_rxd_i 66 | ); 67 | 68 | extint <= iop2(7 downto 4); 69 | iop1(3 downto 0) <= switches_i; 70 | iop1(7 downto 4) <= buttons_i; 71 | 72 | 73 | -- Smoke test logic (to be removed when up and running) ---------------------- 74 | 75 | process(clk) 76 | begin 77 | if clk'event and clk='1' then 78 | if reset = '1' then 79 | leds_o <= "1010"; 80 | else 81 | leds_o <= iop2(3 downto 0); 82 | end if; 83 | end if; 84 | end process; 85 | 86 | end; 87 | 88 | 89 | -- @note1: Clock active if PHYRSTB is high. PHYRSTB pin unused, pulled high. 90 | -------------------------------------------------------------------------------- /syn/zybo_vivado/makefile: -------------------------------------------------------------------------------- 1 | # Generic makefile to build small FPGA project using Vivado toolchain. 2 | # 3 | 4 | #~~~~ Common variables ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | # If we run a shell from any of the goals we want it to be Bash. 7 | SHELL := /bin/bash 8 | 9 | # Put some color in that wall of text. 10 | # Just leave blank if you'd rather get the raw output. 11 | # This does not affect the log files, only the console output. 12 | GREP_HIGHLIGHT = \ 13 | | GREP_COLOR="1;37" grep --color -E '^|ERROR|CRITICAL WARNING|WARNING' 14 | 15 | 16 | #~~~~ Project config ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 17 | 18 | # The project configuration is done entirely in script `build.tcl`. 19 | # (It's only a short list of source and constraint files along with 20 | # some target parameters.) 21 | 22 | # All we need to set up here is the root dir to be passed to the build script. 23 | PROJECT_ROOT = $(realpath ../..) 24 | 25 | 26 | #~~~~ Goals ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 27 | 28 | .PHONY: help 29 | help: 30 | @echo 'Build light8080 demo core for Zybo board using Vivado toolchain.' 31 | @echo 'Goals:' 32 | @echo 33 | @echo 'build - Build project bitstream (in ./output)' 34 | @echo 35 | @echo 'all - Build bitstream and display error/warning summary' 36 | @echo 37 | @echo 'clean - Delete all files created by build' 38 | @echo 39 | @echo 40 | 41 | .default: help 42 | 43 | 44 | # We expect XILINX_VIVADO pointing at the local Vivado install. 45 | # This variable is set by one of Xilinx's setup scripts. 46 | check-vivado-variable: 47 | ifndef XILINX_VIVADO 48 | $(error XILINX_VIVADO is undefined -- maybe run '/opt/Xilinx/Vivado/*/settings64.sh') 49 | endif 50 | 51 | # All output goes into this directory. 52 | output: 53 | mkdir -p output 54 | 55 | # Build bitstream. 56 | .PHONY: build 57 | build: check-vivado-variable output 58 | @echo -e "\e[1;33mRunning Vivado Synth+Impl non-project flow.\e[0m" 59 | cd output; \ 60 | vivado -mode batch -source ../build.tcl -tclargs $(PROJECT_ROOT) $(GREP_HIGHLIGHT) 61 | 62 | # Build bitstream and display a summary of error and warning messages. 63 | .PHONY: all 64 | all: build quickreport 65 | 66 | 67 | # Display a quick summary of errors and warnings by parsing log files. 68 | .PHONY: quickreport 69 | quickreport: 70 | @NUMERR=$(cat output/vivado.log | grep -E "ERROR" | wc -l); \ 71 | echo -e "\e[1;36mError messages: $$NUMERR\e[0m"; \ 72 | cat output/vivado.log | grep --color -E "ERROR" || true 73 | @NUMWARN=$(cat output/vivado.log | grep -E "WARNING|CRITICAL WARNING" | wc -l); \ 74 | echo -e "\e[1;36mWarning messages: $$NUMWARN\e[0m"; \ 75 | cat output/vivado.log | grep --color -E "WARNING|CRITICAL WARNING" || true 76 | 77 | 78 | .PHONY: clean 79 | clean: 80 | @echo -e "\e[1;33mDeleting Vivado project and log files.\e[0m" 81 | rm -rf output 82 | -------------------------------------------------------------------------------- /syn/de1_quartus2/makefile: -------------------------------------------------------------------------------- 1 | # Generic makefile to build small FPGA project using Quartus-2 toolchain. 2 | # 3 | 4 | #~~~~ Common variables ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | # If we run a shell from any of the goals we want it to be Bash. 7 | SHELL := /bin/bash 8 | 9 | # Replace with your own install. 10 | QUARTUS_ROOTDIR ?= /opt/altera/12.1/quartus/bin 11 | 12 | 13 | #~~~~ Project config ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 14 | 15 | # The project configuration is done entirely in script `build.tcl`. 16 | # (It's only a short list of source and constraint files along with 17 | # some target parameters.) 18 | 19 | # All we need to set up here is the root dir to be passed to the build script. 20 | PROJECT_ROOT = $(realpath ../..) 21 | 22 | 23 | #~~~~ Goals ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 24 | 25 | .PHONY: help 26 | help: 27 | @echo 'Build light8080 demo core for DE1 board using Quartus-2 toolchain.' 28 | @echo 'Goals:' 29 | @echo 30 | @echo 'build - Build project bitstream (in ./output)' 31 | @echo 32 | @echo 'all - Build bitstream and display error/warning summary' 33 | @echo 34 | @echo 'clean - Delete all files created by build' 35 | @echo 36 | @echo 37 | 38 | .default: help 39 | 40 | 41 | # All output goes into this directory. 42 | output: 43 | mkdir -p output 44 | 45 | 46 | # One of the flow tools (`TimeQuest Timing Analyzer`) needs the constraints file 47 | # to have the same name as the project, even if we explicitly supply the name. 48 | # We just make two copies of the constraints into the build directory. 49 | copy-constraints: 50 | cp constraints.sdc output 51 | cp constraints.sdc output/de1_demo.sdc 52 | 53 | 54 | # Build bitstream. 55 | .PHONY: build 56 | build: output copy-constraints 57 | @echo -e "\e[1;33mRunning Quartus-2 Synth+Impl flow.\e[0m" 58 | cd output; \ 59 | $(QUARTUS_ROOTDIR)/quartus_sh -t ../build.tcl $(PROJECT_ROOT) 60 | 61 | 62 | # Build bitstream and display a summary of error and bad warning messages. 63 | .PHONY: all 64 | all: build quickreport-critical 65 | 66 | 67 | # Display a quick summary of errors and warnings by parsing log files. 68 | .PHONY: quickreport 69 | quickreport: 70 | @NUMERR=$(cat output/*.*.rpt | grep -E "^\s*Error" | wc -l); \ 71 | echo -e "\e[1;36mError messages: $$NUMERR\e[0m"; \ 72 | cat output/*.*.rpt | grep --color -E "^\s*Error" || true 73 | @NUMWARN=$(cat output/*.*.rpt | grep -E "^\s*Warning|^\s*Critical Warning" | wc -l); \ 74 | echo -e "\e[1;36mWarning messages: $$NUMWARN\e[0m"; \ 75 | cat output/*.*.rpt | grep --color -E "^\s*Warning|^\s*Critical Warning" || true 76 | 77 | .PHONY: quickreport-critical 78 | quickreport-critical: 79 | @NUMERR=$(cat output/*.*.rpt | grep -E "^\s*Error" | wc -l); \ 80 | echo -e "\e[1;36mError messages: $$NUMERR\e[0m"; \ 81 | cat output/*.*.rpt | grep --color -E "^\s*Error" || true 82 | @NUMWARN=$(cat output/*.*.rpt | grep -E "^\s*Critical Warning" | wc -l); \ 83 | echo -e "\e[1;36mWarning messages: $$NUMWARN\e[0m"; \ 84 | cat output/*.*.rpt | grep --color -E "^\s*Critical Warning" || true 85 | 86 | .PHONY: clean 87 | clean: 88 | @echo -e "\e[1;33mDeleting Quartus-2 project and log files.\e[0m" 89 | rm -rf output 90 | -------------------------------------------------------------------------------- /syn/zybo_vivado/build.tcl: -------------------------------------------------------------------------------- 1 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 | # Vivado non-project compilation flow script adapted from UG894. 3 | #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 | # 5 | # Get command line arguments. 6 | if {$argc < 1} { 7 | puts "Missing command line argument." 8 | puts "Usage: $argv0 " 9 | exit 1 10 | } 11 | set PROJECT_ROOT [lindex $argv 0] 12 | # 13 | # STEP#0: project configuration. 14 | set PROJECT_NAME "zybo_demo" 15 | set TOP_MODULE "zybo_top" 16 | set TARGET_CHIP "xc7z010clg400-1" 17 | set RTL_DIR "$PROJECT_ROOT/src/vhdl/rtl" 18 | set BOARD_DIR "$PROJECT_ROOT/boards/zybo" 19 | set OBJ_CODE_DIR "$PROJECT_ROOT/src/sw/diagnostic" 20 | set VHDL_FILES [list \ 21 | "$RTL_DIR/mcu/mcu80_pkg.vhdl" \ 22 | "$OBJ_CODE_DIR/obj_code_pkg.vhdl" \ 23 | "$RTL_DIR/mcu/mcu80_uart.vhdl" \ 24 | "$RTL_DIR/mcu/mcu80_irq.vhdl" \ 25 | "$RTL_DIR/mcu/mcu80.vhdl" \ 26 | "$RTL_DIR/light8080_ucode_pkg.vhdl" \ 27 | "$RTL_DIR/light8080.vhdl" \ 28 | "$BOARD_DIR/zybo_top.vhdl" \ 29 | ] 30 | set XDC_FILES [list \ 31 | "$BOARD_DIR/constraints/vivado-zybo.xdc" \ 32 | ] 33 | #~~~~ From this point onwards the script is mostly generic ~~~~~~~~~~~~~~~~~~~~~ 34 | 35 | # STEP#1: define the output directory area. 36 | # 37 | set outputDir ./$PROJECT_NAME 38 | file mkdir $outputDir 39 | # 40 | # STEP#2: setup design sources and constraints 41 | # 42 | read_vhdl $VHDL_FILES 43 | read_xdc $XDC_FILES 44 | # 45 | # STEP#3: run synthesis, write design checkpoint, report timing, 46 | # and utilization estimates 47 | # 48 | synth_design -top $TOP_MODULE -part $TARGET_CHIP 49 | write_checkpoint -force $outputDir/post_synth.dcp 50 | report_timing_summary -file $outputDir/post_synth_timing_summary.rpt 51 | report_utilization -hierarchical -file $outputDir/post_synth_util.rpt 52 | # 53 | # Run custom script to report critical timing paths 54 | # FIXME TBD 55 | #reportCriticalPaths $outputDir/post_synth_critpath_report.csv 56 | # 57 | # STEP#4: run logic optimization, placement and physical logic optimization, 58 | # write design checkpoint, report utilization and timing estimates 59 | # 60 | opt_design 61 | #FIXME TBD 62 | #reportCriticalPaths $outputDir/post_opt_critpath_report.csv 63 | place_design 64 | report_clock_utilization -file $outputDir/clock_util.rpt 65 | # 66 | # Optionally run optimization if there are timing violations after placement 67 | if {[get_property SLACK [get_timing_paths -max_paths 1 -nworst 1 -setup]] < 0} { 68 | puts "Found setup timing violations => running physical optimization" 69 | phys_opt_design 70 | } 71 | write_checkpoint -force $outputDir/post_place.dcp 72 | report_utilization -file $outputDir/post_place_util.rpt 73 | report_utilization -file $outputDir/post_place_util.hier.rpt -hierarchical 74 | report_timing_summary -file $outputDir/post_place_timing_summary.rpt 75 | # 76 | # STEP#5: run the router, write the post-route design checkpoint, report the routing 77 | # status, report timing, power, and DRC, and finally save the Verilog netlist. 78 | # 79 | route_design 80 | write_checkpoint -force $outputDir/post_route.dcp 81 | report_route_status -file $outputDir/post_route_status.rpt 82 | report_timing_summary -file $outputDir/post_route_timing_summary.rpt 83 | report_power -file $outputDir/post_route_power.rpt 84 | report_drc -file $outputDir/post_imp_drc.rpt 85 | write_verilog -force $outputDir/cpu_impl_netlist.v -mode timesim -sdf_anno true 86 | # 87 | # STEP#6: generate a bitstream 88 | # 89 | write_bitstream -force $outputDir/$PROJECT_NAME.bit 90 | -------------------------------------------------------------------------------- /src/vhdl/rtl/mcu/mcu80_pkg.vhdl: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- mcu80_pkg.vhdl -- Support package for Light8080 MCU. 3 | -- 4 | -- Contains functions used to initialize internal BRAM with object code. 5 | -- 6 | -- This package will be used from the object code package where the program 7 | -- initialized RAM constant is defined. If you use script obj2hdl it will 8 | -- take care of this for you. 9 | -- The package is used in entity mcu80 too, and nowhere else. 10 | -- 11 | -- Please see the LICENSE file in the project root for license matters. 12 | -------------------------------------------------------------------------------- 13 | 14 | library ieee; 15 | use ieee.std_logic_1164.all; 16 | use ieee.numeric_std.all; 17 | 18 | package mcu80_pkg is 19 | 20 | -- Global signals for the TB to use in lieu of hierarchical names. 21 | signal mon_addr : std_logic_vector(15 downto 0); 22 | signal mon_fetch : std_logic; 23 | signal mon_we : std_logic; 24 | signal mon_wdata : std_logic_vector(7 downto 0); 25 | signal mon_uart_ce : std_logic; 26 | 27 | -- Basic array type for the declaration of initialization constants. 28 | -- This type is meant to be used to declare a constant with the object code 29 | -- that is to be preprogrammed in an initialized RAM. 30 | type obj_code_t is array(integer range <>) of std_logic_vector(7 downto 0); 31 | 32 | -- Basic array type for the definition of initialized RAMs. 33 | type ram_t is array(integer range <>) of std_logic_vector(7 downto 0); 34 | 35 | -- Builds BRAM initialization constant from a constant CONSTRAINED byte array 36 | -- containing the application object code. 37 | -- The object code is placed at the beginning of the BRAM and the rest is 38 | -- filled with zeros. 39 | -- CAN BE USED IN SYNTHESIZABLE CODE to compute a BRAM initialization constant 40 | -- from a constant argument. 41 | -- 42 | -- oC: Object code table (as generated by utility script obj2hdl for instance). 43 | -- size: Size of the target memory. 44 | -- Returns ram_t value size-bytes long, suitable for synth-time initialization 45 | -- of a BRAM. 46 | function objcode_to_bram(oC : obj_code_t; size : integer) return ram_t; 47 | 48 | -- Compute log2(A), rounding up. 49 | -- Use this to get the minimum width of the address bus necessary to 50 | -- address A locations. 51 | function log2(A : natural) return natural; 52 | 53 | end package; 54 | 55 | package body mcu80_pkg is 56 | 57 | -- Builds BRAM initialization constant from a constant CONSTRAINED byte array 58 | -- containing the application object code. 59 | function objcode_to_bram(oC : obj_code_t; size : integer) return ram_t is 60 | variable br : ram_t(integer range 0 to size-1); 61 | variable i : integer; 62 | variable obj_size : integer; 63 | begin 64 | 65 | -- If the object code table is longer than the array size, truncate code 66 | if oC'length > size then 67 | obj_size := size; 68 | else 69 | obj_size := oC'length; 70 | end if; 71 | 72 | -- Copy object code to start of BRAM... 73 | for i in 0 to obj_size-1 loop 74 | br(i) := oC(oC'low + i); 75 | end loop; 76 | 77 | -- ... and fill the rest with zeros 78 | br(obj_size to size-1) := (others => x"00"); 79 | 80 | return br; 81 | end function objcode_to_bram; 82 | 83 | 84 | function log2(A : natural) return natural is 85 | begin 86 | for I in 1 to 30 loop -- Works for up to 32 bit integers 87 | if(2**I >= A) then 88 | return(I); 89 | end if; 90 | end loop; 91 | return(30); 92 | end function log2; 93 | 94 | end package body; 95 | -------------------------------------------------------------------------------- /src/vhdl/testbench/light8080_tb_pkg.vhdl: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- light8080_tb_pkg.vhdl -- Support package for Light8080 TBs. 3 | -- 4 | -- Contains procedures and functions used to dump CPU traces, etc. 5 | -- 6 | -- Please see the LICENSE file in the project root for license matters. 7 | -------------------------------------------------------------------------------- 8 | 9 | library ieee; 10 | use ieee.std_logic_1164.all; 11 | use ieee.numeric_std.all; 12 | 13 | use std.textio.all; 14 | use work.txt_util.all; 15 | 16 | use work.mcu80_pkg.all; 17 | 18 | 19 | package light8080_tb_pkg is 20 | 21 | -- Maximum line size of for console output log. Lines longer than this will be 22 | -- truncated. 23 | constant CONSOLE_LOG_LINE_SIZE : integer := 1024*4; 24 | 25 | -- Console log line buffer -------------------------------------- 26 | signal con_line_buf : string(1 to CONSOLE_LOG_LINE_SIZE); 27 | signal con_line_ix : integer; 28 | 29 | 30 | -- Hex representation of std_logic_vector. 31 | function hstr(slv: unsigned) return string; 32 | 33 | -- Every fetch cycle, log the fetch address to file. 34 | -- Loops until done =1. 35 | procedure mon_cpu_trace ( 36 | signal clk : in std_logic; 37 | signal reset : in std_logic; 38 | signal done : inout std_logic; 39 | signal con_line_buf : inout string(1 to CONSOLE_LOG_LINE_SIZE); 40 | signal con_line_ix : inout integer; 41 | file con_file : TEXT; 42 | file log_file : TEXT); 43 | 44 | end package; 45 | 46 | 47 | package body light8080_tb_pkg is 48 | 49 | function hstr(slv: unsigned) return string is 50 | begin 51 | return hstr(std_logic_vector(slv)); 52 | end function hstr; 53 | 54 | procedure mon_cpu_trace ( 55 | signal clk : in std_logic; 56 | signal reset : in std_logic; 57 | signal done : inout std_logic; 58 | signal con_line_buf : inout string(1 to CONSOLE_LOG_LINE_SIZE); 59 | signal con_line_ix : inout integer; 60 | file con_file : TEXT; 61 | file log_file : TEXT) is 62 | begin 63 | 64 | while done = '0' loop 65 | wait until clk'event and clk='1'; 66 | -- For the time being the log only contains fetch addresses. 67 | if mon_fetch = '1' then 68 | print(log_file, ""& hstr(mon_addr)& ": "); 69 | end if; 70 | 71 | 72 | -- Console logging ------------------------------------------------ 73 | if mon_uart_ce = '1' and mon_we = '1' and 74 | mon_addr(1 downto 0) = "00" then 75 | -- UART TX data goes to output after a bit of line-buffering 76 | -- and editing 77 | if mon_wdata = X"0A" then 78 | -- CR received: print output string and clear it 79 | print(con_file, con_line_buf(1 to con_line_ix)); 80 | print(con_line_buf(1 to con_line_ix)); 81 | con_line_ix <= 1; 82 | con_line_buf <= (others => ' '); 83 | elsif mon_wdata = X"0D" then 84 | -- ignore LF. I should be doing the opposite... 85 | elsif mon_wdata = X"04" then 86 | -- EOT terminates simulation. 87 | print("Execution terminated by SW -- EOT written to UART_DATA."); 88 | done <= '1'; 89 | else 90 | -- append char to output string 91 | if con_line_ix < con_line_buf'high then 92 | con_line_buf(con_line_ix) <= 93 | character'val(to_integer(unsigned(mon_wdata))); 94 | con_line_ix <= con_line_ix + 1; 95 | end if; 96 | end if; 97 | end if; 98 | 99 | 100 | 101 | 102 | 103 | end loop; 104 | 105 | end procedure mon_cpu_trace; 106 | 107 | end package body; 108 | -------------------------------------------------------------------------------- /src/vhdl/testbench/mcu80_tb.vhdl: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- mcu80_tb.vhdl -- Minimal test bench for mcu80 (light8080 CPU wrapper). 3 | -- 4 | -------------------------------------------------------------------------------- 5 | 6 | library ieee; 7 | use ieee.std_logic_1164.ALL; 8 | use ieee.numeric_std.ALL; 9 | use std.textio.all; 10 | 11 | 12 | -- Package with utility functions for handling SoC object code. 13 | use work.mcu80_pkg.all; 14 | -- Package that contains the program object code in VHDL constant format. 15 | use work.obj_code_pkg.all; 16 | -- Package with TB support stuff. 17 | use work.light8080_tb_pkg.all; 18 | 19 | 20 | entity mcu80_tb is 21 | end entity mcu80_tb; 22 | 23 | architecture behavior of mcu80_tb is 24 | 25 | -------------------------------------------------------------------------------- 26 | -- Simulation parameters 27 | 28 | -- T: simulated clock period 29 | constant T : time := 100 ns; 30 | 31 | -- MAX_SIM_LENGTH: maximum simulation time 32 | constant MAX_SIM_LENGTH : time := T*70000; -- enough for most purposes 33 | 34 | 35 | -------------------------------------------------------------------------------- 36 | 37 | signal clk : std_logic := '0'; 38 | signal reset : std_logic := '1'; 39 | signal done : std_logic := '0'; 40 | signal interrupts : std_logic_vector(3 downto 0); 41 | signal iop1 : std_logic_vector(7 downto 0); 42 | signal iop2 : std_logic_vector(7 downto 0); 43 | signal txd : std_logic; 44 | signal rxd : std_logic; 45 | 46 | -- Log file... 47 | file log_file: TEXT open write_mode is "hw_sim_log.txt"; 48 | -- ...and console echo file. 49 | file con_file: TEXT open write_mode is "hw_sim_con.txt"; 50 | 51 | begin 52 | 53 | -- Instantiate the Unit Under Test. 54 | uut: entity work.mcu80 55 | generic map ( 56 | OBJ_CODE => work.obj_code_pkg.object_code, 57 | UART_HARDWIRED => false, -- UART baud rate NOT run-time programmable. 58 | UART_IRQ_LINE => 3, -- UART uses IRQ3 line of irq controller. 59 | SIMULATION => True 60 | ) 61 | port map ( 62 | clk => clk, 63 | reset => reset, 64 | 65 | p1_i => iop1, 66 | p2_o => iop2, 67 | 68 | extint_i => "0000", 69 | 70 | rxd_i => txd, -- Plain UART loopback. 71 | txd_o => txd 72 | ); 73 | 74 | 75 | -- clock: Run clock until test is done. 76 | clock: 77 | process(done, clk) 78 | begin 79 | if done = '0' then 80 | clk <= not clk after T/2; 81 | end if; 82 | end process clock; 83 | 84 | 85 | -- main_test: Drive test stimulus, basically let CPU run after reset. 86 | main_test: 87 | process 88 | begin 89 | -- Assert reset for at least one full clk period 90 | reset <= '1'; 91 | wait until clk = '1'; 92 | wait for T/2; 93 | reset <= '0'; 94 | 95 | -- Remember to 'cut away' the preceding 3 clk semiperiods from 96 | -- the wait statement... 97 | wait until done='1' for (MAX_SIM_LENGTH - T*1.5); 98 | 99 | -- If we get here with done = '0', the test timed out. 100 | assert (done = '1') 101 | report "Test timed out." 102 | severity failure; 103 | 104 | if iop2 = X"55" then 105 | report "Test PASSED." 106 | severity note; 107 | else 108 | report "Test FAILED." 109 | severity failure; 110 | end if; 111 | 112 | wait; 113 | end process main_test; 114 | 115 | 116 | -- Logging process: launch logger functions -------------------------------- 117 | 118 | 119 | log_execution: 120 | process 121 | begin 122 | con_line_ix <= 1; 123 | con_line_buf <= (others => ' '); 124 | -- Log cpu activity until done='1'. 125 | mon_cpu_trace( 126 | clk, reset, done, 127 | con_line_buf, con_line_ix, 128 | con_file, log_file); 129 | 130 | wait; 131 | end process log_execution; 132 | 133 | end; 134 | -------------------------------------------------------------------------------- /src/sw/hello/obj_code_pkg.vhdl: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- obj_code_pkg.vhdl -- Application object code in vhdl constant string format. 3 | -------------------------------------------------------------------------------- 4 | -- Written by build_rom.py for project 'hello'. 5 | -------------------------------------------------------------------------------- 6 | -- 7 | -- This source file may be used and distributed without 8 | -- restriction provided that this copyright statement is not 9 | -- removed from the file and that any derivative work contains 10 | -- the original copyright notice and the associated disclaimer. 11 | -- 12 | -- This source file is free software; you can redistribute it 13 | -- and/or modify it under the terms of the GNU Lesser General 14 | -- Public License as published by the Free Software Foundation; 15 | -- either version 2.1 of the License, or (at your option) any 16 | -- later version. 17 | -- 18 | -- This source is distributed in the hope that it will be 19 | -- useful, but WITHOUT ANY WARRANTY; without even the implied 20 | -- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 21 | -- PURPOSE. See the GNU Lesser General Public License for more 22 | -- details. 23 | -- 24 | -- You should have received a copy of the GNU Lesser General 25 | -- Public License along with this source; if not, download it 26 | -- from http://www.opencores.org/lgpl.shtml 27 | -------------------------------------------------------------------------------- 28 | 29 | library ieee; 30 | use ieee.std_logic_1164.all; 31 | use ieee.numeric_std.all; 32 | 33 | -- Package with utility functions for handling SoC object code. 34 | use work.mcu80_pkg.all; 35 | 36 | package obj_code_pkg is 37 | 38 | -- Object code initialization constant. 39 | constant object_code : obj_code_t(0 to 248) := ( 40 | X"c3", X"60", X"00", X"00", X"00", X"00", X"00", X"00", -- 0000h : 0007h 41 | X"c9", X"00", X"00", X"00", X"00", X"00", X"00", X"00", -- 0008h : 000fh 42 | X"c9", X"00", X"00", X"00", X"00", X"00", X"00", X"00", -- 0010h : 0017h 43 | X"c9", X"00", X"00", X"00", X"00", X"00", X"00", X"00", -- 0018h : 001fh 44 | X"c9", X"00", X"00", X"00", X"00", X"00", X"00", X"00", -- 0020h : 0027h 45 | X"c9", X"00", X"00", X"00", X"00", X"00", X"00", X"00", -- 0028h : 002fh 46 | X"c9", X"00", X"00", X"00", X"00", X"00", X"00", X"00", -- 0030h : 0037h 47 | X"c3", X"b0", X"00", X"00", X"00", X"00", X"00", X"00", -- 0038h : 003fh 48 | X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", -- 0040h : 0047h 49 | X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", -- 0048h : 004fh 50 | X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", -- 0050h : 0057h 51 | X"00", X"00", X"00", X"00", X"00", X"00", X"00", X"00", -- 0058h : 005fh 52 | X"31", X"5c", X"01", X"21", X"f7", X"00", X"22", X"f8", -- 0060h : 0067h 53 | X"00", X"21", X"fc", X"00", X"22", X"fa", X"00", X"3e", -- 0068h : 006fh 54 | X"14", X"d3", X"83", X"3e", X"58", X"d3", X"82", X"3e", -- 0070h : 0077h 55 | X"00", X"d3", X"86", X"3e", X"08", X"d3", X"88", X"fb", -- 0078h : 007fh 56 | X"21", X"9e", X"00", X"cd", X"e7", X"00", X"3e", X"55", -- 0080h : 0087h 57 | X"d3", X"86", X"3e", X"04", X"d3", X"80", X"db", X"84", -- 0088h : 008fh 58 | X"4f", X"07", X"07", X"81", X"d3", X"86", X"c3", X"8e", -- 0090h : 0097h 59 | X"00", X"f3", X"76", X"c3", X"9b", X"00", X"0a", X"0d", -- 0098h : 009fh 60 | X"0a", X"48", X"65", X"6c", X"6c", X"6f", X"20", X"57", -- 00a0h : 00a7h 61 | X"6f", X"72", X"6c", X"64", X"21", X"0a", X"24", X"00", -- 00a8h : 00afh 62 | X"e5", X"f5", X"db", X"81", X"e6", X"20", X"ca", X"c9", -- 00b0h : 00b7h 63 | X"00", X"3e", X"20", X"d3", X"81", X"db", X"80", X"d3", -- 00b8h : 00bfh 64 | X"86", X"2a", X"fa", X"00", X"77", X"23", X"22", X"fa", -- 00c0h : 00c7h 65 | X"00", X"db", X"81", X"e6", X"10", X"ca", X"e3", X"00", -- 00c8h : 00cfh 66 | X"3e", X"10", X"d3", X"81", X"2a", X"f8", X"00", X"7e", -- 00d0h : 00d7h 67 | X"fe", X"24", X"ca", X"e3", X"00", X"23", X"22", X"f8", -- 00d8h : 00dfh 68 | X"00", X"d3", X"80", X"f1", X"e1", X"fb", X"c9", X"7e", -- 00e0h : 00e7h 69 | X"23", X"22", X"f8", X"00", X"fe", X"24", X"ca", X"f6", -- 00e8h : 00efh 70 | X"00", X"d3", X"80", X"c3", X"e7", X"00", X"c9", X"24", -- 00f0h : 00f7h 71 | X"00" -- 00f8h : 00f8h 72 | 73 | ); 74 | 75 | 76 | end package obj_code_pkg; 77 | 78 | -------------------------------------------------------------------------------- /src/sw/common/common.mk: -------------------------------------------------------------------------------- 1 | # Makefile fragment -- see $(PROJECTDIR)/sim/{ghdl|icarus}/makefile 2 | #------------------------------------------------------------------------------- 3 | # Build some test SW and optionally execute it on the TB for mcu80 using GHDL. 4 | # 5 | # This makefile fragment is meant to be included from the makefile for the SW 6 | # in question. $(CURDIR) is meant to be the SW dir. 7 | # BUT you really should invoke the simulation from $(PROJECTDIR)/sim. 8 | # 9 | # See help text below. 10 | # 11 | # Equivalent targets for the Verilog version of the project, using Icarus, will 12 | # be added eventually. 13 | #------------------------------------------------------------------------------- 14 | 15 | # Use bash for shell commands like echo. 16 | SHELL := /bin/bash 17 | 18 | 19 | #---- Assembler configuration. Adapt to your own setup. ------------------------ 20 | 21 | # Relative to SW dir. 22 | # FIXME part of pending refactor. Clean up! 23 | PROJECTDIR := ../../.. 24 | 25 | 26 | # Assembler, ASL. 27 | ASM := $(PROJECTDIR)/tools/asl/install/bin/asl 28 | AFLAGS := -L -G 29 | # Object code formatter. ASL does not support linking. 30 | OBJ2HEX := $(PROJECTDIR)/tools/asl/install/bin/p2hex 31 | OFLAGS := -F Intel 32 | 33 | # Assembly extension is 'mac' for ASL by convention in light8080. 34 | ASM_EXT := mac 35 | # Object code extension is hardcoded to 'p' in ASL. 36 | OBJ_EXT := p 37 | 38 | #---- Simulator configuration. ------------------------------------------------- 39 | 40 | # GHDL. 41 | GHDLC := ghdl 42 | GHDLFLAGS := 43 | GHDLSIMFLAGS := --ieee-asserts=disable 44 | # GtkWave. 45 | WAVE := gtkwave 46 | 47 | #---- Utilities. --------------------------------------------------------------- 48 | 49 | # ihex-to-vhdl/verilog object code conversion script -- part of light8080. 50 | ROM_RTL := $(PROJECTDIR)/tools/build_rom/src/build_rom.py 51 | ROM_RTL_FLAGS := --quiet 52 | # TODO This is an example, it's not used yet. 53 | ROM_RTL_DEFINES := +define+A=45 54 | 55 | 56 | #---- Defaults. ---------------------------------------------------------------- 57 | 58 | # Default values for RTL files. 59 | VHDL_PKG_NAME ?= obj_code_pkg.vhdl 60 | VLOG_INC_NAME ?= obj_code.inc.v 61 | 62 | 63 | 64 | #---- Some help text ----------------------------------------------------------- 65 | 66 | .DEFAULT: help 67 | .PHONY: help 68 | help: 69 | @echo "Use this makefile to build SW samples included within the project." 70 | @echo 71 | @echo "GOALS:" 72 | @echo " sw ..................... Build program \$$PROJ_NAME (defaults to 'diagnostic')" 73 | @echo " Object code is generated as a ROM-able constant " 74 | @echo " within a VHDL package and a Verilog include file" 75 | @echo " help ................... Show this help text" 76 | @echo " clean .................. Regular clean goal" 77 | @echo 78 | @echo "You'll need 8080 assembler ASL installed." 79 | @echo "The makefile within \$$PROJECT/tools will install it locally for you." 80 | @echo 81 | 82 | #---- Vars & rules common to all code samples. --------------------------------- 83 | 84 | # SW sources. 85 | # All assembly files in directory get assembled. Only assembly supported. 86 | ASM_SRC := $(wildcard *.${ASM_EXT}) 87 | 88 | # Output name is first name of list. 89 | # This is how asXXXX worked, we do the same for ASL. Doesn't matter. 90 | OBJ := $(addsuffix .${OBJ_EXT}, $(basename $(word 1, ${ASM_SRC}))) 91 | HEX := $(addsuffix .ihx, $(basename $(word 1, ${ASM_SRC}))) 92 | 93 | # Will be nonempty if ASL assembler is actually there. 94 | ASL_INSTALLED := $(shell command -v ${ASM} 2> /dev/null) 95 | 96 | # If ASL is not installed, echo some useful advice. 97 | .PHONY: check_assembler_install 98 | check_assembler_install: 99 | ifndef ASL_INSTALLED 100 | @echo -e "\e[1;31mCould not find ASL assembler at the expected path.\e[0m" 101 | @echo -e "\e[1;37mThere's a makefile at \$$PROJECT/tools that will install a local copy for you.\e[0m" 102 | @echo -e "\e[1;37m(Contained within this project, no root privileges needed, no mess. You need git & gcc though.)\e[0m" 103 | @echo -e "\e[1;37mIf you install it manually elsewhere make sure to fix the path in \$$PROJECT/src/sw/common/common.mk.\e[0m" 104 | endif 105 | 106 | 107 | # Assembler. All files get fed at once. 108 | ${OBJ}: check_assembler_install ${ASM_SRC} 109 | ifndef ASL_INSTALLED 110 | $(error ASL assembler not found at the expected path. Please install it or fix makefile) 111 | endif 112 | $(ASM) $(AFLAGS) ${ASM_SRC} 113 | 114 | # Linker. 115 | # ASL does not have a linker as such; this step is a p-to-hex reformatter. 116 | .PHONY: bin 117 | bin: ${OBJ} 118 | ${OBJ2HEX} ${OBJ} ${HEX} ${LFLAGS} 119 | 120 | # VHDL package generator. 121 | .PHONY: vhdl 122 | vhdl: bin 123 | @echo Building VHDL package \'$(VHDL_PKG_NAME)\' 124 | @$(ROM_RTL) --project=$(PROJ_NAME) --output=$(VHDL_PKG_NAME) \ 125 | $(ROM_RTL_FLAGS) \ 126 | $(HEX) \ 127 | $(ROM_RTL_DEFINES) 128 | 129 | # Verilog include file generator. 130 | # TODO add support for Verilog! 131 | .PHONY: verilog 132 | verilog: bin 133 | @echo Building Verilog include file \'$(VLOG_INC_NAME)\' 134 | 135 | # Build SW, generate ROM files for RTL simulation. 136 | .PHONY: sw 137 | sw: vhdl verilog 138 | 139 | .PHONY: clean 140 | clean: 141 | rm -rf *.lst *.map *.rel *.sym *.p *.ihx *.vhdl *.v 142 | $(GHDLC) --clean 143 | rm -rf *.vcd *.ghw *.cf 144 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # light8080 2 | Synthesizable i8080-compatible CPU core. 3 | 4 | (This project lived in [OpenCores](https://opencores.org/project,light8080) until late '16, and a copy will remain there as long as OpenCores is up. See below.) 5 | 6 | ## Description 7 | 8 | This is a simple, small microprogrammed Intel 8080 CPU binary compatible core. 9 | 10 | There are already at least two other 8080-compatible cores in Opencores, both of them well proven. This one is different because it emphasizes area instead of cycle-count compatibility or speed. 11 | 12 | I have tried to minimize logic size and complexity as much as possible, at the expense of speed. At about the same size as a Picoblaze on a Spartan 3 (204 LUTs + 1 BRAM), this is perhaps amongst the smallest 8-bit CPU cores available. On the other hand, it is rather slow in clock frequency and particularly in cycles per instruction (25 to 50% more clocks per instruction than the original, which is an awful lot! -- see the design notes). Besides, the 2 KBytes of dedicated fpga ram it does use may in some designs be more valuable than a large number of logic blocks. 13 | 14 | The source is quite simple: a single RTL file with some 970 lines of straightforward, moderately commented VHDL code; plus a microcode package file ~530 lines long with the microcode ROM data. However, the simplicity may be deceptive; it can be argued that the complexity of the system has been moved from the RTL to the microcode... 15 | 16 | A description of the circuit and its microcode is included in the design notes and the respective source files. The microcode assembler (a Python script) is included too, as well as the microcode source from which the VHDL uCode ROM table was built, though it is not necessary if you just want to use the core and not modify it. 17 | 18 | This is just a fun project I created back in 2007 to learn vhdl; my design goal was to get the simplest possible 8080-compatible core, at the smallest possible size, at any reasonable speed. And above all, at a minimum cost in development time -- so I could get something worthy done in the very limited time available. 19 | Though I think I accomplished my goal, the resulting core is probably of little practical use: it is certainly no match for a picoblaze in its application niche, and it is not small enough to compensate for its lack of features (the smallest Nios II is only 2 or 3 times larger). And there are better 8080 cores around, as I said. 20 | 21 | I am in debt with Scott A. Moore for [his cpu8080 core](http://opencores.org/project,cpu8080). Though I have not used his code in this project, I studied it and did use much of the research and test material that he made available. 22 | 23 | 24 | 25 | ## Features 26 | 27 | - Microcoded design, very simple circuit. 28 | - Microcode source and assembler included, though the vhdl microcode table can be edited directly. 29 | - Slower than original in clocks per instructions (about 25 to 50%, comparative table included in the design notes). 30 | - 100% binary compatible to original 8080. 31 | - Synchronized to positive clock edges only. 32 | - Signal interface very simplified. Not all original status info available (no M1, for instance). 33 | - Synchronous memory and i/o interface, with NO WAIT STATE ability. 34 | - INTA procedure similar to original 8080, except it can use any instruction as int vector. 35 | - Undefined/unused opcodes are NOPs. 36 | 37 | 38 | 39 | ### Performance (standalone CPU, synthesis only): 40 | 41 | 1. Xilinx XST on Spartan 3 (-5 grade): 42 | * 204 LUTs plus 1 BRAM @ 80 MHz (optimized for area) 43 | * 228 LUTs plus 1 BRAM @ 100 MHz (optimized for speed) 44 | * 618 LUTs @ 53 MHz (optimized for area, no block ram) 45 | 46 | 2. Altera Quartus on Cyclone 2: 47 | * 369 LEs plus 4 M4Ks @ 67 MHz (balanced optimization) 48 | 49 | 3. Xilinx Vivado on Zynq-7000 (XC7Z010-1CLG400C): 50 | * 334 LUTs (no BRAMs) @ 125 MHz (clock constrained to 125MHz, 0.45 ns slack) 51 | 52 | _(Note that the Zynq build uses no BRAM for the microcode, thanks to the 6 input LUTs mostly.)_ 53 | 54 | 55 | ## Status 56 | 57 | The core has already executed some quite large pieces of original code in hardware, including the Microsoft Altair 4K Basic. 58 | Interrupt response has been simulated and tested in real hardware (but test 59 | sources not yet moved to this repo!). 60 | The project includes a minimal MCU system built around the CPU core that can be useful as an usage example or as the starting point for a real application. 61 | 62 | Besides, thanks to Moti Litochevski the project is now available in both Verilog and VHDL versions (but only on the OpenCores site, Verilog port not moved to GitHub yet!). 63 | 64 | 65 | Compatibility to the original Intel 8080 has not yet been achieved at 100% -- the CY flag undocumented behavior for some logic instructions is slightly incompatible. This is an issue that can't be fixed without a lot of testing with original 8080 chips, or with very accurate simulators. 66 | 67 | 68 | Please note that the documented behavior of the CPU is 100% compatible to the original; it's only the *undocumented* behavior of the original silicon that has not yet been fully replicated -- only almost. 69 | We have set up some demos to showcase the core. 70 | 71 | 72 | 73 | ## Portage to GitHub 74 | 75 | This core used to be at [OpenCores](https://opencores.org/project,light8080). I moved it here in late '16 and slightly refactored it. 76 | These are the differences: 77 | 78 | * Project used to rely on DOS Batch files, now it uses Makefiles and is Linux-centric. 79 | * Simulations used to rely on Modelsim. Now I've included makefiles and updated RTL to use GHDL... 80 | * ...although of course you can use whatever simulator you want. 81 | * Verilog version made by Moti Litochevski not moved yet to GitHub... 82 | * ...and this includes some other goodies Moti added to the project, including a free Small C compiler port. 83 | * Demos, including Altair 4K Basic, not moved yet to GitHub. 84 | * Project used to be tested on Xilinx ISE. Now it includes synthesis scripts for Vivado only... 85 | * ...because I no longer have a functional install of ISE. 86 | * Microcode ROM data extracted to a separate VHDL package. 87 | * Microcode assembler rewritten from scratch in Python. 88 | 89 | 90 | 91 | This list is mostly a reminder to myself of things that remain to be done on this project. The project as it stands here in GitHub should be usable (inasmuch as an 8080 core is usable). 92 | 93 | 94 | -------------------------------------------------------------------------------- /src/sw/hello/hello.mac: -------------------------------------------------------------------------------- 1 | ;******************************************************************************* 2 | ; hello.mac -- light8080 core basic demo: 'Hello World!" 3 | ;******************************************************************************* 4 | ; Should be used with MCU wrapper vhdl\mcu\mcu80.vhdl 5 | ; Assembler format compatible with ASL on Linux. 6 | ;******************************************************************************* 7 | ; This program will print a Hello message to the MCU UART, then will loop 8 | ; forever copying the input port P1 to the output port P2 doing some arith to 9 | ; convince you the CPU is alive: 10 | ; P2 = P1 | (P1 << 2) 11 | ; This demo is meant to be used as a starting point for those crowds anxiously 12 | ; wanting to play with the mcu80 core -- which in turn is little more than an 13 | ; usage example for the light8080 cpu core. 14 | ;******************************************************************************* 15 | 16 | 17 | cpu 8080 18 | aseg 19 | 20 | 21 | org 0H 22 | 23 | MASK_RX_IRQ equ 20H 24 | MASK_TX_IRQ equ 10H 25 | MASK_RX_RDY equ 02H 26 | MASK_TX_RDY equ 01H 27 | 28 | UART_DATA equ 80H 29 | UART_STATUS equ 81H 30 | UART_BAUDL equ 82H 31 | UART_BAUDH equ 83H 32 | IRQ_ENABLE equ 88H 33 | P1IN equ 84H 34 | P2OUT equ 86H 35 | 36 | 37 | ;******************************************************************************* 38 | 39 | 40 | jmp start ; Skip the rst address area 41 | 42 | ;***** Interrupt vectors in area 0008h-0038h ***************** 43 | 44 | org 08H ; interrupt vector 1 45 | ret 46 | org 10H ; interrupt vector 2 47 | ret 48 | org 18H ; interrupt vector 3 49 | ret 50 | org 20H ; interrupt vector 4 51 | ret 52 | org 28H ; interrupt vector 5 53 | ret 54 | org 30H ; interrupt vector 6 55 | ret 56 | 57 | org 38H ; interrupt vector 7 58 | int38h: jmp irq_uart ; UART interrupt 59 | 60 | 61 | ;***** program entry point ******************************************* 62 | 63 | 64 | org 60H 65 | start: lxi sp,stack 66 | 67 | ; Initialize UART RX and TX buffers 68 | lxi h,void_buffer 69 | shld ptr_tx 70 | lxi h,rx_buffer 71 | shld ptr_rx 72 | ; Set up UART baud rate to 9600 bauds @ 50MHz: 73 | ; (50E6 / 9600) = 5208d = 1458h 74 | mvi a,14h 75 | out UART_BAUDH 76 | mvi a,58h 77 | out UART_BAUDL 78 | 79 | ; Clear P2 port 80 | mvi a,0h 81 | out P2OUT 82 | 83 | ; Set up interrupts 84 | mvi a,08h ; Enable UART irq... 85 | out IRQ_ENABLE 86 | ei ; ...and enable interrupts in the CPU 87 | 88 | ; print hello message to console 89 | lxi h,msg_hello 90 | call print_string 91 | 92 | ; Write 55h to port P2. This will be caught as 'test pass' outcome 93 | ; by the simulation TB. 94 | mvi a,55h 95 | out P2OUT 96 | ; Now write EOF to UART_DATA. This terminates the TB. 97 | mvi a,04h 98 | out UART_DATA 99 | 100 | 101 | forever: 102 | in P1IN 103 | mov c,a 104 | rlc 105 | rlc 106 | add c 107 | out P2OUT 108 | jmp forever 109 | 110 | di 111 | hlt 112 | done: jmp done 113 | 114 | msg_hello: db "\n\r\nHello World!\n$\000" 115 | 116 | ;irq_uart: UART interrupt processing 117 | irq_uart: 118 | push h 119 | push psw 120 | 121 | ; Deal with RX interrupt (if any) first and then the TX interrupt. 122 | in UART_STATUS ; Is there new data in the RX register? 123 | ani MASK_RX_IRQ 124 | jz irq_uart_rx_done ; If there isn't, process TX interrupt. 125 | 126 | ; Process UART RX interrupt 127 | irq_uart_rx: 128 | mvi a,MASK_RX_IRQ ; Clear IRQ flag. 129 | out UART_STATUS 130 | in UART_DATA ; Get RX byte... 131 | out P2OUT ; ...display it in the output port... 132 | lhld ptr_rx ; ...and store it in the rx buffer. 133 | mov m,a 134 | inx h 135 | shld ptr_rx ; Update the rx buffer pointer. 136 | ; Note there's no check for RX buffer overrun! 137 | 138 | irq_uart_rx_done: 139 | ; Ok, RX is done. Now deal with TX irq, if any 140 | in UART_STATUS ; Is the TX buffer re new data in the RX register? 141 | ani MASK_TX_IRQ 142 | jz irq_uart_end ; If there isn't, we're done. 143 | 144 | ; process UART TX interrupt 145 | irq_uart_tx: 146 | mvi a,MASK_TX_IRQ ; Clear IRQ flag. 147 | out UART_STATUS 148 | lhld ptr_tx ; Get next byte from the TX buffer 149 | mov a,m 150 | cpi '$' ; Did we reach the end of the buffer? 151 | jz irq_uart_tx_done ; If we did, we're done here... 152 | inx h ; ...otherwise increment the TX pointer... 153 | shld ptr_tx 154 | out UART_DATA ; ...and transmit the data byte. 155 | 156 | irq_uart_tx_done: 157 | 158 | irq_uart_end: 159 | pop psw ; Done, quit. 160 | pop h 161 | ei 162 | ret 163 | ; Note there's no check for RX buffer overrun! we shouldn't need it 164 | ; in this program, anyway. 165 | 166 | 167 | ;print_string: print $-terminated string at HL 168 | ; Returns as soon as the transmission has started; transmission proceeds in 169 | ; 'background' through the UART interrupt service routine. 170 | print_string: 171 | ; We don't check if there's a transmission going on, we just start 172 | ; transmitting. Not suitable for real use! 173 | print_string_loop: 174 | mov a,m ; Get first character from string... 175 | inx h ; ...and move updated string pointer to TX 176 | shld ptr_tx ; buffer pointer. 177 | cpi '$' ; Kickstart transmission by sending 1st byte... 178 | jz print_string_end; ...unless its the end of string marker. 179 | out UART_DATA ; 180 | jmp print_string_loop 181 | print_string_end: 182 | ret 183 | 184 | 185 | ; data space, placed immediately after object code in memory 186 | void_buffer: db "$" 187 | ptr_tx: ds 2 188 | ptr_rx: ds 2 189 | rx_buffer: ds 32 190 | ds 64 191 | stack: ds 2 192 | end 193 | 194 | -------------------------------------------------------------------------------- /src/vhdl/rtl/mcu/mcu80_irq.vhdl: -------------------------------------------------------------------------------- 1 | --############################################################################## 2 | -- mcu80_l80irq : Interrupt controller for light8080-based mcu80 MCU. 3 | --############################################################################## 4 | -- 5 | -- This is a basic interrupt controller for the light8080 core. It is meant for 6 | -- demonstration purposes only (demonstration of the light8080 core) and has 7 | -- not passed any serious verification test bench. 8 | -- It has been built on the same principles as the rest of the modules in this 9 | -- project: no more functionality than strictly needed, minimized area. 10 | -- 11 | -- The interrupt controller operates under these rules: 12 | -- 13 | -- -# All interrupt inputs are active at rising edge. 14 | -- -# No logic is included for input sinchronization. You must take care to 15 | -- prevent metastability issues yourself by the usual means. 16 | -- -# If a new edge is detected before the first is serviced, it is lost. 17 | -- -# As soon as a rising edge in enabled irq input K is detected, bit K in the 18 | -- interrupt pending register 'irq_pending_reg' will be asserted. 19 | -- Than is, disabled interrupts never get detected at all. 20 | -- -# Output cpu_intr_o will be asserted as long as there's a bit asserted in 21 | -- the interrupt pending register. 22 | -- -# For each interrupt there is a predefined priority level and a predefined 23 | -- interrupt vector -- see comments below. 24 | -- -# As soon as an INTA cycle is done by the CPU (inta=1 and fetch=1) the 25 | -- following will happen: 26 | -- * The module will supply the interrupt vector of the highes priority 27 | -- pending interrupt. 28 | -- * The highest priority pending interrupt bit in the pending interrupt 29 | -- register will be deasserted -- UNLESS the interrupts happens to trigger 30 | -- again at the same time, in which case the pending bit will remain 31 | -- asserted. 32 | -- * If there are no more interrupts pending, the cpu_intr_o output will 33 | -- be deasserted. 34 | -- -# The CPU will have its interrupts disabled from the INTA cycle to the 35 | -- execution of instruction EI. 36 | -- -# The cpu_intr_o will be asserted for a single cycle. 37 | -- -# The irq vectors are hardcoded to RST instructions (single byte calls). 38 | -- 39 | -- The priorities and vectors are hardcoded to the following values: 40 | -- 41 | -- irq_i(3) Priority 3 Vector RST 7 42 | -- irq_i(2) Priority 2 Vector RST 5 43 | -- irq_i(1) Priority 1 Vector RST 3 44 | -- irq_i(0) Priority 0 Vector RST 1 45 | -- 46 | -- (Priority order: 3 > 2 > 1 > 0). 47 | -- 48 | -- This module is used in the mcu80 module, for which a basic test bench 49 | -- exists. Both can be used as usage example. 50 | -- The module and its application is so simple than no documentation other than 51 | -- these comments should be necessary. 52 | -- 53 | -- Please see the LICENSE file in the project root for license matters. 54 | --############################################################################## 55 | 56 | library ieee; 57 | use ieee.std_logic_1164.all; 58 | use ieee.numeric_std.all; 59 | 60 | --############################################################################## 61 | -- 62 | --############################################################################## 63 | 64 | entity mcu80_irq is 65 | port ( 66 | cpu_inta_i : in std_logic; 67 | cpu_intr_o : out std_logic; 68 | cpu_fetch_i : in std_logic; 69 | 70 | data_we_i : in std_logic; 71 | addr_i : in std_logic; 72 | data_i : in std_logic_vector(7 downto 0); 73 | data_o : out std_logic_vector(7 downto 0); 74 | 75 | irq_i : in std_logic_vector(3 downto 0); 76 | 77 | clk : in std_logic; 78 | reset : in std_logic 79 | ); 80 | end mcu80_irq; 81 | 82 | --############################################################################## 83 | -- 84 | --############################################################################## 85 | 86 | architecture hardwired of mcu80_irq is 87 | 88 | -- irq_pending: 1 when irq[i] is pending service 89 | signal irq_pending_reg : std_logic_vector(3 downto 0); 90 | -- irq_enable: 1 when irq[i] is enabled 91 | signal irq_enable_reg : std_logic_vector(3 downto 0); 92 | -- irq_q: registered irq input used to catch rising edges 93 | signal irq_q : std_logic_vector(3 downto 0); 94 | -- irq_trigger: asserted to 1 when a rising edge is detected 95 | signal irq_trigger : std_logic_vector(3 downto 0); 96 | signal irq_clear : std_logic_vector(3 downto 0); 97 | signal irq_clear_mask:std_logic_vector(3 downto 0); 98 | 99 | signal data_rd : std_logic_vector(7 downto 0); 100 | signal vector : std_logic_vector(7 downto 0); 101 | signal irq_level : std_logic_vector(2 downto 0); 102 | 103 | 104 | begin 105 | 106 | edge_detection: 107 | for i in 0 to 3 generate 108 | begin 109 | irq_trigger(i) <= '1' when -- IRQ(i) is triggered when... 110 | irq_q(i)='0' and -- ...we see a rising edge... 111 | irq_i(i)='1' and 112 | irq_enable_reg(i)='1' -- ...and the irq input us enabled. 113 | else '0'; 114 | end generate edge_detection; 115 | 116 | interrupt_pending_reg: 117 | process(clk) 118 | begin 119 | if clk'event and clk='1' then 120 | if reset = '1' then 121 | irq_pending_reg <= (others => '0'); 122 | irq_q <= (others => '0'); 123 | else 124 | irq_pending_reg <= (irq_pending_reg and (not irq_clear)) or irq_trigger; 125 | irq_q <= irq_i; 126 | end if; 127 | end if; 128 | end process interrupt_pending_reg; 129 | 130 | with irq_level select irq_clear_mask <= 131 | "1000" when "111", 132 | "0100" when "101", 133 | "0010" when "011", 134 | "0001" when others; 135 | 136 | irq_clear <= irq_clear_mask when cpu_inta_i='1' and cpu_fetch_i='1' else "0000"; 137 | 138 | 139 | interrupt_enable_reg: 140 | process(clk) 141 | begin 142 | if clk'event and clk='1' then 143 | if reset = '1' then 144 | -- All interrupts disabled at reset 145 | irq_enable_reg <= (others => '0'); 146 | else 147 | if data_we_i = '1' and addr_i = '0' then 148 | irq_enable_reg <= data_i(3 downto 0); 149 | end if; 150 | end if; 151 | end if; 152 | end process interrupt_enable_reg; 153 | 154 | -- Interrupt priority & vector decoding 155 | irq_level <= 156 | "001" when irq_pending_reg(0) = '1' else 157 | "011" when irq_pending_reg(1) = '1' else 158 | "110" when irq_pending_reg(2) = '1' else 159 | "111"; 160 | 161 | -- Raise interrupt request when there's any irq pending 162 | cpu_intr_o <= '1' when irq_pending_reg /= "0000" else '0'; 163 | 164 | -- The IRQ vector is hardcoded to a RST instruction, whose opcode is 165 | -- RST ---> 11nnn111 166 | process(clk) 167 | begin 168 | if clk'event and clk='1' then 169 | if cpu_inta_i='1' and cpu_fetch_i='1' then 170 | vector <= "11" & irq_level & "111"; 171 | end if; 172 | end if; 173 | end process; 174 | 175 | -- There's only an internal register, the irq enable register, so we 176 | -- don't need an output register mux. 177 | data_rd <= "0000" & irq_enable_reg; 178 | 179 | -- The mdule will output the register being read, if any, OR the irq vector. 180 | data_o <= vector when cpu_inta_i = '1' else data_rd; 181 | 182 | 183 | 184 | 185 | end hardwired; 186 | 187 | -------------------------------------------------------------------------------- /tools/build_rom/src/build_rom.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | build_rom.py: Create VHDL package with ROM initialization constant from 4 | Intel-HEX object code file. 5 | Please use with --help to get some brief usage instructions. 6 | """ 7 | 8 | import sys 9 | import os 10 | import argparse 11 | 12 | TAG_BOTTOM_ADDR = "@bottom_addr@" 13 | TAG_TOP_ADDR = "@top_addr@" 14 | TAG_PKGNAME = "@obj_pkg_name@" 15 | TAG_CODEBYTES = "@obj_bytes@" 16 | TAG_PROJNAME = "@project_name@" 17 | 18 | 19 | DEFAULT_VHDL_OUTPUT_NAME = "obj_code_pkg.vhdl" 20 | DEFAULT_VERILOG_OUTPUT_NAME = "obj_code.inc.v" 21 | 22 | FORMAT_VERILOG = 'verilog' 23 | FORMAT_VHDL = 'vhdl' 24 | FORMAT_CHOICES = [FORMAT_VHDL, FORMAT_VERILOG] 25 | 26 | def _build_vhdl_package(data_array, bottom, top, opts): 27 | """ """ 28 | 29 | # Open template file and read it into a list of lines. 30 | script_dir = os.path.dirname(__file__) 31 | template_filename = os.path.join(script_dir, "..","templates", "template.vhdl") 32 | try: 33 | fin = open(template_filename, "r") 34 | lines = fin.readlines() 35 | fin.close() 36 | except IOError as e: 37 | print e 38 | sys.exit(e.errno) 39 | 40 | code_bytes = "" 41 | code_line = " "*4 42 | i = 0 43 | print "Range: %d to %d" %(bottom, top) 44 | for addr in range(bottom, top+1): 45 | b = data_array[addr] 46 | if addr < top: 47 | code_line += "X\"%02x\", " % b 48 | else: 49 | code_line += "X\"%02x\" " % b 50 | if (i % 8) == 7: 51 | code_bytes += code_line + " -- %04xh : %04xh\n" % (addr-7, addr) 52 | code_line = " "*4 53 | i = 0 54 | else: 55 | i = i + 1 56 | if len(code_line.strip()) > 0: 57 | code_bytes += " "*4 + "%-56s -- %04xh : %04xh\n" % (code_line.strip(), addr-i+1, addr) 58 | 59 | vhdl = "" 60 | for line in lines: 61 | line = line.replace(TAG_BOTTOM_ADDR, "%d" % bottom) 62 | line = line.replace(TAG_TOP_ADDR, "%d" % top) 63 | line = line.replace(TAG_PKGNAME, "obj_code_pkg") 64 | line = line.replace(TAG_PROJNAME, opts.project) 65 | line = line.replace(TAG_CODEBYTES, code_bytes) 66 | vhdl += line 67 | 68 | return vhdl 69 | 70 | 71 | def _build_verilog_include(data_array, bottom, top, opts): 72 | pass 73 | 74 | def _parse_hex_line(line): 75 | """Parse code line in HEX object file.""" 76 | line = line.strip() 77 | slen = int(line[1:3],16) 78 | sloc = int(line[3:7],16) 79 | stype = line[7:9] 80 | sdata = line[9:len(line)-2] 81 | schk = int(line[len(line)-2:],16) 82 | 83 | csum = slen + int(sloc / 256) + (sloc % 256) + int(stype,16) 84 | bytes = [0, ] * slen 85 | for i in range(slen): 86 | sbyte = int(sdata[i*2:i*2+2],16) 87 | bytes[i] = sbyte; 88 | csum = csum + sbyte 89 | 90 | csum = ~csum 91 | csum = csum + 1 92 | csum = csum % 256 93 | if csum != schk: 94 | return (None, None) 95 | 96 | return (sloc, bytes) 97 | 98 | 99 | def _read_ihex_file(ihex_filename, quiet=False, fill=0): 100 | """ 101 | Read Intel HEX file into a 64KB array. 102 | The file is assumed not to have any object code outside the range [0:64K-1]. 103 | Return the 64K array plus the size and bounds of the read data. 104 | Array locations not initialized by hex file are filled with supplied value. 105 | """ 106 | 107 | # CODE array, initialized to 64K of zeros... 108 | xcode = [fill, ] * 65536 109 | # ...and code boundaries, initialized out of range. 110 | bottom = 100000 111 | top = -1 112 | (xcode, top, bottom) 113 | 114 | # Read the whole file to a list of lines... 115 | try: 116 | fin = open(ihex_filename, "r") 117 | ihex_lines = fin.readlines() 118 | fin.close() 119 | except IOError as e: 120 | print e 121 | sys.exit(e.errno) 122 | 123 | # ...and parse the lines one by one. 124 | total_bytes = 0 125 | for line in ihex_lines: 126 | (address, bytes) = _parse_hex_line(line) 127 | if address == None: 128 | print >> sys.stderr, "Checksum error in object file!" 129 | sys.exit(1) 130 | total_bytes = total_bytes + len(bytes) 131 | for i in range(len(bytes)): 132 | xcode[address + i] = bytes[i] 133 | 134 | if address < bottom: 135 | bottom = address 136 | 137 | if (address + len(bytes)) > top: 138 | top = (address + len(bytes)) 139 | 140 | if not quiet: 141 | print >> sys.stdout, "Read %d bytes from file '%s'" % (total_bytes, ihex_filename) 142 | print >> sys.stdout, "Code range %04xh to %04xh" % (bottom, top) 143 | return (xcode, total_bytes, bottom, top) 144 | 145 | def _parse_cmdline(argv): 146 | 147 | parser = argparse.ArgumentParser( 148 | description='Produce ROM initialization data in VHDL/Verilog format.') 149 | 150 | parser.add_argument( 151 | 'object', 152 | type=str, 153 | help='Object code file in Intel HEX format.') 154 | parser.add_argument( 155 | '--project', 156 | type=str, 157 | default="(unknown)", 158 | help='Name of SW project. To be used in comments only.') 159 | parser.add_argument( 160 | '--format', 161 | choices=FORMAT_CHOICES, 162 | default='vhdl', 163 | help="Output format (one of %s)." % ",".join(FORMAT_CHOICES)) 164 | parser.add_argument( 165 | '--output', 166 | type=str, 167 | default=None, 168 | help='Output file path. Defaults to same as object file with suitable extension vhdl/v.') 169 | parser.add_argument( 170 | '--memsize', 171 | type=int, 172 | default=4*1024, 173 | help='Size of target memory block in bytes. Defaults to 4KB.') 174 | parser.add_argument( 175 | '--membase', 176 | type=int, 177 | default=0, 178 | help='Base address of target memory block. Defaults to 0.') 179 | parser.add_argument( 180 | '--quiet', 181 | action='store_true', 182 | default=False, 183 | help='Supress all chatter form console output.') 184 | parser.add_argument( 185 | 'parameters', 186 | type=str, 187 | metavar='+define+NAME=VALUE', 188 | nargs='*', 189 | default=0, 190 | help='Parameter definition.') 191 | 192 | 193 | opts = parser.parse_args() 194 | 195 | # Set output file name if none is given. 196 | if not opts.output: 197 | if opts.format == FORMAT_VHDL: 198 | opts.output = DEFAULT_VHDL_OUTPUT_NAME 199 | elif opts.format == FORMAT_VERILOG: 200 | opts.output = DEFAULT_VERILOG_OUTPUT_NAME 201 | else: 202 | # Should not happen but... 203 | print >> sys.stderr, "Invalid output format '%s'." % opts.format 204 | sys.exit(2) 205 | 206 | 207 | return opts 208 | 209 | def _main(argv): 210 | 211 | opts = _parse_cmdline(argv) 212 | 213 | (objcode, total_bytes, bottom, top) = _read_ihex_file(opts.object, opts.quiet) 214 | 215 | if opts.format == 'vhdl': 216 | rtl = _build_vhdl_package(objcode, bottom, top, opts) 217 | elif opts.format == 'verilog': 218 | rtl = _build_verilog_include(objcode, bottom, top, opts) 219 | else: 220 | print >> sys.stderr, "Invalid output format '%s'." % opts.format 221 | sys.exit(2) 222 | 223 | 224 | # Done. Write to output file and quit. 225 | try: 226 | fo = open(opts.output, "w") 227 | print >> fo, rtl 228 | #fo.close() 229 | except IOError as e: 230 | print e 231 | sys.exit(e.errno) 232 | 233 | 234 | 235 | if __name__ == "__main__": 236 | _main(sys.argv[1:]) 237 | sys.exit(0) 238 | 239 | -------------------------------------------------------------------------------- /boards/de1/de1_top.vhdl: -------------------------------------------------------------------------------- 1 | --############################################################################## 2 | -- Light8080 MPU demo on Terasic's DE-1 board. 3 | --############################################################################## 4 | -- 5 | -- This is a minimal demo of the light8080 MPU wrapper targetting Terasic's DE-1 6 | -- development board for Cyclone-2 FPGAs. 7 | -- Since the demo uses little board resources other than the serial port it 8 | -- should be easy to port it to other platforms. 9 | -- 10 | -- The MPU entity contains a block of RAM that is used for both program and 11 | -- data. The BRAM is initialized at synthesis time with a constant taken from 12 | -- package 'obj_code_pkg'. This package can be built from an object code file 13 | -- in Intel HEX format with utility '/tools/build_rom' included with this 14 | -- project. There's an example of this in the TB makefiles. 15 | -- 16 | -- This demo has been built from a generic template for designs targetting the 17 | -- DE-1 development board. The entity defines all the inputs and outputs present 18 | -- in the actual board, whether or not they are used in the design at hand. 19 | --############################################################################## 20 | 21 | library ieee; 22 | use ieee.std_logic_1164.all; 23 | use ieee.numeric_std.all; 24 | 25 | -- Package that contains the program object code in VHDL constant format. 26 | use work.obj_code_pkg.all; 27 | 28 | 29 | -- Define the entity outputs as they are connected in the DE-1 development 30 | -- board. Many of the outputs will be left unused in this demo. 31 | entity DE1_TOP is 32 | port ( 33 | -- ***** Clocks 34 | clk_50MHz : in std_logic; 35 | 36 | -- ***** Flash 4MB 37 | flash_addr : out std_logic_vector(21 downto 0); 38 | flash_data : in std_logic_vector(7 downto 0); 39 | flash_oe_n : out std_logic; 40 | flash_we_n : out std_logic; 41 | flash_reset_n : out std_logic; 42 | 43 | -- ***** SRAM 256K x 16 44 | sram_addr : out std_logic_vector(17 downto 0); 45 | sram_data : inout std_logic_vector(15 downto 0); 46 | sram_oe_n : out std_logic; 47 | sram_ub_n : out std_logic; 48 | sram_lb_n : out std_logic; 49 | sram_ce_n : out std_logic; 50 | sram_we_n : out std_logic; 51 | 52 | -- ***** RS-232 53 | rxd : in std_logic; 54 | txd : out std_logic; 55 | 56 | -- ***** Switches and buttons 57 | switches : in std_logic_vector(9 downto 0); 58 | buttons : in std_logic_vector(3 downto 0); 59 | 60 | -- ***** Quad 7-seg displays 61 | hex0 : out std_logic_vector(0 to 6); 62 | hex1 : out std_logic_vector(0 to 6); 63 | hex2 : out std_logic_vector(0 to 6); 64 | hex3 : out std_logic_vector(0 to 6); 65 | 66 | -- ***** Leds 67 | red_leds : out std_logic_vector(9 downto 0); 68 | green_leds : out std_logic_vector(7 downto 0); 69 | 70 | -- ***** SD Card 71 | sd_data : in std_logic; 72 | sd_cs : out std_logic; 73 | sd_cmd : out std_logic; 74 | sd_clk : out std_logic 75 | ); 76 | end DE1_TOP; 77 | 78 | architecture minimal of DE1_TOP is 79 | 80 | --############################################################################## 81 | -- MCU and immediate glue logic. 82 | 83 | -- light8080 MCU signals ------------------------------------------------------- 84 | signal p1in : std_logic_vector(7 downto 0); 85 | signal p2out : std_logic_vector(7 downto 0); 86 | signal uart_txd : std_logic; 87 | signal uart_rxd : std_logic; 88 | signal extint : std_logic_vector(3 downto 0); 89 | 90 | -- Signals for external SRAM synchronization ----------------------------------- 91 | signal sram_data_out : std_logic_vector(7 downto 0); -- sram output reg 92 | signal sram_write : std_logic; -- sram we register 93 | signal address_reg : std_logic_vector(15 downto 0); -- registered addr bus 94 | 95 | 96 | --############################################################################## 97 | -- On-board device interface signals. 98 | 99 | -- Quad 7-segment display (non multiplexed) & LEDS ----------------------------- 100 | signal display_data : std_logic_vector(15 downto 0); 101 | 102 | 103 | -- Clock & reset signals ------------------------------------------------------- 104 | signal clk_1hz : std_logic; 105 | signal clk_master : std_logic; 106 | signal reset : std_logic; 107 | signal clk : std_logic; 108 | signal counter_1hz : unsigned(25 downto 0); 109 | 110 | -- SD control signals ---------------------------------------------------------- 111 | -- SD connector unused, unconnected 112 | 113 | 114 | --## Functions ################################################################# 115 | 116 | -- Converts hex nibble to 7-segment (sinthesizable). 117 | -- Segments ordered as "GFEDCBA"; '0' is ON, '1' is OFF 118 | function nibble_to_7seg(nibble : std_logic_vector(3 downto 0)) 119 | return std_logic_vector is 120 | begin 121 | case nibble is 122 | when X"0" => return "0000001"; 123 | when X"1" => return "1001111"; 124 | when X"2" => return "0010010"; 125 | when X"3" => return "0000110"; 126 | when X"4" => return "1001100"; 127 | when X"5" => return "0100100"; 128 | when X"6" => return "0100000"; 129 | when X"7" => return "0001111"; 130 | when X"8" => return "0000000"; 131 | when X"9" => return "0000100"; 132 | when X"a" => return "0001000"; 133 | when X"b" => return "1100000"; 134 | when X"c" => return "0110001"; 135 | when X"d" => return "1000010"; 136 | when X"e" => return "0110000"; 137 | when X"f" => return "0111000"; 138 | when others => return "0111111"; -- can't happen 139 | end case; 140 | end function nibble_to_7seg; 141 | 142 | begin 143 | 144 | 145 | -- MCU instantiation. 146 | mcu: entity work.mcu80 147 | generic map ( 148 | OBJ_CODE => work.obj_code_pkg.object_code, 149 | UART_HARDWIRED => false, -- UART baud rate NOT run-time programmable. 150 | UART_IRQ_LINE => 3, -- UART uses IRQ3 line of irq controller. 151 | BAUD_RATE => 115200, -- UART baud rate. 152 | CLOCK_FREQ => 125E6 -- Clock frequency in Hz. 153 | ) 154 | port map ( 155 | clk => clk, 156 | reset => reset, 157 | 158 | p1_i => p1in, 159 | p2_o => p2out, 160 | 161 | extint_i => extint, 162 | 163 | txd_o => uart_txd, 164 | rxd_i => uart_rxd 165 | ); 166 | 167 | 168 | 169 | 170 | -- Input port connected to switches for lack of better use 171 | p1in <= switches(7 downto 0); 172 | 173 | 174 | --##### Input ports ########################################################### 175 | 176 | 177 | --############################################################################## 178 | -- terasIC Cyclone II STARTER KIT BOARD 179 | --############################################################################## 180 | 181 | --############################################################################## 182 | -- FLASH (flash is unused in this demo) 183 | --############################################################################## 184 | 185 | flash_addr <= (others => '0'); 186 | 187 | flash_we_n <= '1'; -- all enable signals inactive 188 | flash_oe_n <= '1'; 189 | flash_reset_n <= '1'; 190 | 191 | 192 | --############################################################################## 193 | -- SRAM (wired as 64K x 8) 194 | -- The SRAM is unused in this demo. 195 | --############################################################################## 196 | 197 | -- These registera make the external, asynchronous SRAM behave like an 198 | -- internal syncronous BRAM, except for the timing. 199 | -- Since the SoC has no wait state capability, the SoC clock rate must 200 | -- accomodate the SRAM timing -- including FPGA clock-to-output, RAM delays 201 | -- and FPGA input setup and hold times. Setting up the synthesis constraints 202 | -- is left to the user too. 203 | sram_registers: 204 | process(clk) 205 | begin 206 | if clk'event and clk='1' then 207 | if reset='1' then 208 | sram_addr <= "000000000000000000"; 209 | address_reg <= "0000000000000000"; 210 | sram_data_out <= X"00"; 211 | sram_write <= '0'; 212 | else 213 | end if; 214 | end if; 215 | end process sram_registers; 216 | 217 | sram_data(15 downto 8) <= "ZZZZZZZZ"; -- high byte unused 218 | sram_data(7 downto 0) <= "ZZZZZZZZ" when sram_write='0' else sram_data_out; 219 | -- (the X"ZZ" will physically be the read input data) 220 | 221 | -- sram access controlled by WE_N 222 | sram_oe_n <= '0'; 223 | sram_ce_n <= '0'; 224 | sram_we_n <= not sram_write; 225 | sram_ub_n <= '1'; -- always disable 226 | sram_lb_n <= '0'; 227 | 228 | 229 | --############################################################################## 230 | -- RESET, CLOCK 231 | --############################################################################## 232 | 233 | -- Use button 0 as reset 234 | reset <= not buttons(0); 235 | 236 | 237 | -- Generate a 1-Hz 'clock' to flash a LED for visual reference. 238 | process(clk_50MHz) 239 | begin 240 | if clk_50MHz'event and clk_50MHz='1' then 241 | if reset = '1' then 242 | clk_1hz <= '0'; 243 | counter_1hz <= (others => '0'); 244 | else 245 | if to_integer(counter_1hz) = 50000000 then 246 | counter_1hz <= (others => '0'); 247 | clk_1hz <= not clk_1hz; 248 | else 249 | counter_1hz <= counter_1hz + 1; 250 | end if; 251 | end if; 252 | end if; 253 | end process; 254 | 255 | -- Master clock is external 50MHz oscillator 256 | clk <= clk_50MHz; 257 | 258 | 259 | --############################################################################## 260 | -- LEDS, SWITCHES 261 | --############################################################################## 262 | 263 | -- Display the contents of an output port at the green leds bar 264 | green_leds <= p2out; 265 | 266 | -- Red leds unused except for 1-Hz clock 267 | red_leds(9 downto 1) <= (others => '0'); 268 | red_leds(0) <= clk_1hz; 269 | 270 | 271 | --############################################################################## 272 | -- QUAD 7-SEGMENT DISPLAYS 273 | --############################################################################## 274 | 275 | -- Display the contents of the output port at the hex displays. 276 | --display_data <= X"42" & switches(7 downto 0); --p2out & p1in; 277 | display_data <= p2out & p1in; 278 | 279 | -- 7-segment encoders; the dev board displays are not multiplexed or encoded 280 | hex3 <= nibble_to_7seg(display_data(15 downto 12)); 281 | hex2 <= nibble_to_7seg(display_data(11 downto 8)); 282 | hex1 <= nibble_to_7seg(display_data( 7 downto 4)); 283 | hex0 <= nibble_to_7seg(display_data( 3 downto 0)); 284 | 285 | 286 | --############################################################################## 287 | -- SD card interface 288 | --############################################################################## 289 | 290 | -- SD card unused in this demo 291 | sd_cs <= '0'; 292 | sd_cmd <= '0'; 293 | sd_clk <= '0'; 294 | --sd_in <= '0'; 295 | 296 | 297 | --############################################################################## 298 | -- SERIAL 299 | --############################################################################## 300 | 301 | -- Txd & rxd connected straight to the SoC 302 | txd <= uart_txd; 303 | uart_rxd <= rxd; 304 | 305 | 306 | end minimal; 307 | -------------------------------------------------------------------------------- /src/vhdl/rtl/mcu/mcu80.vhdl: -------------------------------------------------------------------------------- 1 | --############################################################################## 2 | -- mcu80_mcu : light8080-based Micro Controller Unit 3 | --############################################################################## 4 | -- This MCU is meant as an usage example for the light8080 core. The code shows 5 | -- how to interface the core to internal BRAM and other modules. 6 | -- This module is not meant to be used in real applications though it can be 7 | -- used as the starting point for one. 8 | -- 9 | -- Please see the comments below for usage instructions. 10 | -- Please see the LICENSE file in the project root for license matters. 11 | --############################################################################## 12 | 13 | library ieee; 14 | use ieee.std_logic_1164.all; 15 | use ieee.numeric_std.all; 16 | 17 | use work.mcu80_pkg.all; 18 | 19 | 20 | --############################################################################## 21 | -- Interface pins: 22 | ------------------ 23 | -- p1_i : Input port P1. 24 | -- p2_o : Output port P2. 25 | -- rxd_i : UART RxD pin. 26 | -- txd_o : UART TxD pin. 27 | -- extint_i : External interrupt inputs, wired straight to the irq controller. 28 | -- EXCEPT for the one used by the UART -- see generic UART_IRQ_LINE. 29 | -- clk : Master clock, rising edge active. 30 | -- reset : Synchronous reset, 1 cycle active to reset all SoC. 31 | -- 32 | -------------------------------------------------------------------------------- 33 | -- Generics: 34 | ------------ 35 | -- OBJ_CODE (mandatory, no default value): 36 | -- Table that will be used to initialize internal BRAM, starting at address 0. 37 | -- 38 | -- DEFAULT_RAM_SIZE (default = 0): 39 | -- Internal RAM size. If set to zero, the RAM size will be determined from the 40 | -- size of OBJ_CODE as the smallest power of 2 larger than OBJ_CODE'length. 41 | -- 42 | -- UART_IRQ_LINE (defaults to 4): 43 | -- Index of the irq controller input the internal UART is wired to, or >3 to 44 | -- leave the UART unconnected to the IRQ controller. 45 | -- The irq controller input used for the uart will be unconnected to the SoC 46 | -- input port. 47 | -- 48 | -- UART_HARDWIRED (defaults to true): 49 | -- True when the UART baud rate is hardwired. the baud rate registers will be 50 | -- 51 | -- BAUD_RATE (defaults to 19200): 52 | -- UART default baud rate. When th UART is hardwired, the baud rate can't be 53 | -- changed at run time. 54 | -- Note that you have to set generic z. This value is needed to compute the 55 | -- UART baud rate constants. 56 | -- 57 | -- SIMULATION (Defaults to False): 58 | -- When True, a number of internal signals are connected to global package 59 | -- signals. 60 | -- This gives the TB access to those signals without using VHDL2008 features 61 | -- (not yet supported in GHDL) or equivalent proprietary schemes. 62 | -- Set it to True in the TB, ignore it otherwise. 63 | -------------------------------------------------------------------------------- 64 | -- I/O port map: 65 | ---------------- 66 | -- 67 | -- 080h..083h UART registers. 68 | -- 084h P1 input port (read only, writes are ignored). 69 | -- 086h P2 output port (write only, reads undefined data). 70 | -- 088h IRQ enable register. 71 | -- 72 | -- Please see the comments in the source of the relevant modules for a more 73 | -- detailed explanation of their behavior. 74 | -- 75 | -- All i/o ports other than the above read as 00h. 76 | -------------------------------------------------------------------------------- 77 | -- Notes: 78 | --------- 79 | -- -# If you do not set a default memory size, you then have to take care to 80 | -- control the size of the object code table. 81 | -- -# If you do set the default memory size, the code will not warn you if the 82 | -- object code does not fit inside, it will silentl truncate it. 83 | -- -# The internal memory block is mirrored over the entire address map. 84 | -- -# There is no write protection to any address range: you can overwrite the 85 | -- program. If you do that there's no way to recover it but reloading the 86 | -- FPGA, a reset will not do. 87 | --############################################################################## 88 | entity mcu80 is 89 | generic ( 90 | OBJ_CODE : obj_code_t; -- RAM initialization constant 91 | DEFAULT_RAM_SIZE: integer := 0; -- RAM size or 0 to stretch 92 | UART_IRQ_LINE : integer := 4; -- [0..3] or >3 for none 93 | UART_HARDWIRED: boolean := true; -- UART baud rate is hardwired 94 | BAUD_RATE : integer := 19200; -- UART (default) baud rate 95 | CLOCK_FREQ : integer := 50E6; -- Clock frequency in Hz 96 | SIMULATION : boolean := False -- True when instantiated in TB 97 | ); 98 | port ( 99 | p1_i : in std_logic_vector(7 downto 0); 100 | p2_o : out std_logic_vector(7 downto 0); 101 | 102 | rxd_i : in std_logic; 103 | txd_o : out std_logic; 104 | 105 | extint_i : in std_logic_vector(3 downto 0); 106 | 107 | clk : in std_logic; 108 | reset : in std_logic 109 | ); 110 | end mcu80; 111 | 112 | --############################################################################## 113 | -- 114 | --############################################################################## 115 | 116 | architecture hardwired of mcu80 is 117 | 118 | -- Helper functions ------------------------------------------------------------ 119 | 120 | 121 | -- soc_ram_size: compute size of internal RAM 122 | -- If default_size is /= 0, the size is the default. If it is zero, then the 123 | -- size the smallest power of 2 larger than obj_code_size. 124 | function soc_ram_size(default_size, obj_code_size: integer) return integer is 125 | begin 126 | if default_size=0 then 127 | -- Default is zero: use a RAM as big as necessary for the obj code table 128 | -- rounding to the neares power of 2. 129 | return 2**log2(obj_code_size); 130 | else 131 | -- Default is not zero: use the default and do NOT check to see if the 132 | -- object code fits. 133 | return default_size; 134 | end if; 135 | end function soc_ram_size; 136 | 137 | -- Custom types ---------------------------------------------------------------- 138 | 139 | subtype t_byte is std_logic_vector(7 downto 0); 140 | subtype io_addr_t is unsigned(7 downto 0); 141 | 142 | -- CPU signals ----------------------------------------------------------------- 143 | 144 | signal cpu_vma : std_logic; 145 | signal cpu_rd : std_logic; 146 | signal cpu_wr : std_logic; 147 | signal cpu_io : std_logic; 148 | signal cpu_fetch : std_logic; 149 | signal cpu_addr : std_logic_vector(15 downto 0); 150 | signal cpu_data_i : std_logic_vector(7 downto 0); 151 | signal cpu_data_o : std_logic_vector(7 downto 0); 152 | signal cpu_intr : std_logic; 153 | signal cpu_inte : std_logic; 154 | signal cpu_inta : std_logic; 155 | signal cpu_halt : std_logic; 156 | 157 | 158 | -- Aux CPU signals ------------------------------------------------------------- 159 | 160 | -- io_wr: asserted in IO write cycles 161 | signal io_wr : std_logic; 162 | -- io_rd: asserted in IO read cycles 163 | signal io_rd : std_logic; 164 | -- io_addr: IO port address, lowest 8 bits of address bus 165 | signal io_addr : unsigned(7 downto 0); 166 | -- io_rd_data: data coming from IO ports (io input mux) 167 | signal io_rd_data : std_logic_vector(7 downto 0); 168 | -- cpu_io_reg: registered cpu_io, used to control mux after cpu_io deasserts 169 | signal cpu_io_reg : std_logic; 170 | 171 | -- UART ------------------------------------------------------------------------ 172 | 173 | signal uart_ce : std_logic; 174 | signal uart_data_rd : std_logic_vector(7 downto 0); 175 | signal uart_irq : std_logic; 176 | 177 | 178 | -- RAM ------------------------------------------------------------------------- 179 | 180 | constant RAM_SIZE : integer := soc_ram_size(DEFAULT_RAM_SIZE,OBJ_CODE'length); 181 | constant RAM_ADDR_SIZE : integer := log2(RAM_SIZE); 182 | 183 | signal ram_rd_data : std_logic_vector(7 downto 0); 184 | signal ram_we : std_logic; 185 | 186 | signal ram : ram_t(0 to RAM_SIZE-1) := objcode_to_bram(OBJ_CODE, RAM_SIZE); 187 | signal ram_addr : unsigned(RAM_ADDR_SIZE-1 downto 0); 188 | 189 | -- IRQ controller interface ---------------------------------------------------- 190 | 191 | signal irqcon_we : std_logic; 192 | signal irqcon_data_rd: std_logic_vector(7 downto 0); 193 | signal irq : std_logic_vector(3 downto 0); 194 | 195 | 196 | -- IO ports addresses ---------------------------------------------------------- 197 | 198 | constant ADDR_UART_0 : io_addr_t := X"80"; -- UART registers (80h..83h) 199 | constant ADDR_UART_1 : io_addr_t := X"81"; -- UART registers (80h..83h) 200 | constant ADDR_UART_2 : io_addr_t := X"82"; -- UART registers (80h..83h) 201 | constant ADDR_UART_3 : io_addr_t := X"83"; -- UART registers (80h..83h) 202 | constant P1_DATA_REG : io_addr_t := X"84"; -- port 1 data register 203 | constant P2_DATA_REG : io_addr_t := X"86"; -- port 2 data register 204 | constant INTR_EN_REG : io_addr_t := X"88"; -- interrupts enable register 205 | 206 | 207 | begin 208 | 209 | 210 | cpu: entity work.light8080 211 | port map ( 212 | clk => clk, 213 | reset => reset, 214 | vma => cpu_vma, 215 | rd => cpu_rd, 216 | wr => cpu_wr, 217 | io => cpu_io, 218 | fetch => cpu_fetch, 219 | addr_out => cpu_addr, 220 | data_in => cpu_data_i, 221 | data_out => cpu_data_o, 222 | 223 | intr => cpu_intr, 224 | inte => cpu_inte, 225 | inta => cpu_inta, 226 | halt => cpu_halt 227 | ); 228 | 229 | io_rd <= cpu_io and cpu_rd; 230 | io_wr <= '1' when cpu_io='1' and cpu_wr='1' else '0'; 231 | io_addr <= unsigned(cpu_addr(7 downto 0)); 232 | 233 | -- Register some control signals that are needed to control multiplexors the 234 | -- cycle after the control signal asserts -- e.g. cpu_io. 235 | control_signal_registers: 236 | process(clk) 237 | begin 238 | if clk'event and clk='1' then 239 | cpu_io_reg <= cpu_io; 240 | end if; 241 | end process control_signal_registers; 242 | 243 | -- Input data mux -- remember, no 3-state buses within the FPGA -------------- 244 | cpu_data_i <= 245 | irqcon_data_rd when cpu_inta = '1' else 246 | io_rd_data when cpu_io_reg = '1' else 247 | ram_rd_data; 248 | 249 | 250 | -- BRAM ---------------------------------------------------------------------- 251 | 252 | ram_we <= '1' when cpu_io='0' and cpu_wr='1' else '0'; 253 | ram_addr <= unsigned(cpu_addr(RAM_ADDR_SIZE-1 downto 0)); 254 | 255 | memory: 256 | process(clk) 257 | begin 258 | if clk'event and clk='1' then 259 | if ram_we = '1' then 260 | ram(to_integer(ram_addr)) <= cpu_data_o; 261 | end if; 262 | ram_rd_data <= ram(to_integer(ram_addr)); 263 | end if; 264 | end process memory; 265 | 266 | 267 | -- Interrupt controller ------------------------------------------------------ 268 | -- FIXME interrupts unused in this version 269 | 270 | irq_control: entity work.mcu80_irq 271 | port map ( 272 | clk => clk, 273 | reset => reset, 274 | 275 | irq_i => irq, 276 | 277 | data_i => cpu_data_o, 278 | data_o => irqcon_data_rd, 279 | addr_i => cpu_addr(0), 280 | data_we_i => irqcon_we, 281 | 282 | cpu_inta_i => cpu_inta, 283 | cpu_intr_o => cpu_intr, 284 | cpu_fetch_i => cpu_fetch 285 | ); 286 | 287 | irq_line_connections: 288 | for i in 0 to 3 generate 289 | begin 290 | uart_irq_connection: 291 | if i = UART_IRQ_LINE generate 292 | begin 293 | irq(i) <= uart_irq or extint_i(i); 294 | end generate; 295 | other_irq_connections: 296 | if i /= UART_IRQ_LINE generate 297 | irq(i) <= extint_i(i); 298 | end generate; 299 | end generate irq_line_connections; 300 | 301 | irqcon_we <= '1' when io_addr=INTR_EN_REG and io_wr='1' else '0'; 302 | 303 | -- UART -- simple UART with hardwired baud rate ------------------------------ 304 | -- NOTE: the serial port does NOT have interrupt capability (yet) 305 | 306 | uart : entity work.mcu80_uart 307 | generic map ( 308 | BAUD_RATE => BAUD_RATE, 309 | CLOCK_FREQ => CLOCK_FREQ 310 | ) 311 | port map ( 312 | clk_i => clk, 313 | reset_i => reset, 314 | 315 | irq_o => uart_irq, 316 | data_i => cpu_data_o, 317 | data_o => uart_data_rd, 318 | addr_i => cpu_addr(1 downto 0), 319 | 320 | ce_i => uart_ce, 321 | wr_i => io_wr, 322 | rd_i => io_rd, 323 | 324 | rxd_i => rxd_i, 325 | txd_o => txd_o 326 | ); 327 | 328 | -- UART write enable 329 | uart_ce <= '1' when 330 | io_addr(7 downto 2) = ADDR_UART_0(7 downto 2) 331 | else '0'; 332 | 333 | -- IO ports -- Simple IO ports with hardcoded direction ---------------------- 334 | -- These are meant as an usage example mostly 335 | 336 | output_ports: 337 | process(clk) 338 | begin 339 | if clk'event and clk='1' then 340 | if reset = '1' then 341 | -- Reset values for all io ports 342 | p2_o <= (others => '0'); 343 | else 344 | if io_wr = '1' then 345 | if to_integer(io_addr) = P2_DATA_REG then 346 | p2_o <= cpu_data_o; 347 | end if; 348 | end if; 349 | end if; 350 | end if; 351 | end process output_ports; 352 | 353 | -- Input IO data multiplexor 354 | with io_addr select io_rd_data <= 355 | p1_i when P1_DATA_REG, 356 | uart_data_rd when ADDR_UART_0, 357 | uart_data_rd when ADDR_UART_1, 358 | uart_data_rd when ADDR_UART_2, 359 | uart_data_rd when ADDR_UART_3, 360 | irqcon_data_rd when INTR_EN_REG, 361 | X"00" when others; 362 | 363 | 364 | -- Simulation support ------------------------------------------------------ 365 | 366 | Internal_signal_extraction: 367 | if SIMULATION generate 368 | -- 'Connect' all the internal signals we want to watch to members of 369 | -- the info record. 370 | -- This does not require VHDL 2008 support or proprietary tricks. 371 | mon_addr <= cpu_addr; 372 | mon_fetch <= cpu_fetch; 373 | mon_wdata <= cpu_data_o; 374 | mon_we <= cpu_wr; 375 | mon_uart_ce <= uart_ce; 376 | end generate Internal_signal_extraction; 377 | 378 | end hardwired; 379 | 380 | -------------------------------------------------------------------------------- /src/vhdl/testbench/txt_util.vhdl: -------------------------------------------------------------------------------- 1 | -- No license information available, assumed to be in public domain. 2 | library ieee; 3 | use ieee.std_logic_1164.all; 4 | use std.textio.all; 5 | 6 | 7 | package txt_util is 8 | 9 | -- prints a message to the screen 10 | procedure print(text: string); 11 | 12 | -- prints the message when active 13 | -- useful for debug switches 14 | procedure print(active: boolean; text: string); 15 | 16 | -- converts std_logic into a character 17 | function chr(sl: std_logic) return character; 18 | 19 | -- converts std_logic into a string (1 to 1) 20 | function str(sl: std_logic) return string; 21 | 22 | -- converts std_logic_vector into a string (binary base) 23 | function str(slv: std_logic_vector) return string; 24 | 25 | -- converts boolean into a string 26 | function str(b: boolean) return string; 27 | 28 | -- converts an integer into a single character 29 | -- (can also be used for hex conversion and other bases) 30 | function chr(int: integer) return character; 31 | 32 | -- converts integer into string using specified base 33 | function str(int: integer; base: integer) return string; 34 | 35 | -- converts integer to string, using base 10 36 | function str(int: integer) return string; 37 | 38 | -- convert std_logic_vector into a string in hex format 39 | function hstr(slv: std_logic_vector) return string; 40 | 41 | 42 | -- functions to manipulate strings 43 | ----------------------------------- 44 | 45 | -- convert a character to upper case 46 | function to_upper(c: character) return character; 47 | 48 | -- convert a character to lower case 49 | function to_lower(c: character) return character; 50 | 51 | -- convert a string to upper case 52 | function to_upper(s: string) return string; 53 | 54 | -- convert a string to lower case 55 | function to_lower(s: string) return string; 56 | 57 | 58 | 59 | -- functions to convert strings into other formats 60 | -------------------------------------------------- 61 | 62 | -- converts a character into std_logic 63 | function to_std_logic(c: character) return std_logic; 64 | 65 | -- converts a string into std_logic_vector 66 | function to_std_logic_vector(s: string) return std_logic_vector; 67 | 68 | 69 | 70 | -- file I/O 71 | ----------- 72 | 73 | -- read variable length string from input file 74 | procedure str_read(file in_file: TEXT; 75 | res_string: out string); 76 | 77 | -- print string to a file and start new line 78 | procedure print(file out_file: TEXT; 79 | new_string: in string); 80 | 81 | -- print character to a file and start new line 82 | procedure print(file out_file: TEXT; 83 | char: in character); 84 | 85 | end txt_util; 86 | 87 | 88 | 89 | 90 | package body txt_util is 91 | 92 | 93 | 94 | 95 | -- prints text to the screen 96 | 97 | procedure print(text: string) is 98 | variable msg_line: line; 99 | begin 100 | write(msg_line, text); 101 | writeline(output, msg_line); 102 | end print; 103 | 104 | 105 | 106 | 107 | -- prints text to the screen when active 108 | 109 | procedure print(active: boolean; text: string) is 110 | begin 111 | if active then 112 | print(text); 113 | end if; 114 | end print; 115 | 116 | 117 | -- converts std_logic into a character 118 | 119 | function chr(sl: std_logic) return character is 120 | variable c: character; 121 | begin 122 | case sl is 123 | when 'U' => c:= 'U'; 124 | when 'X' => c:= 'X'; 125 | when '0' => c:= '0'; 126 | when '1' => c:= '1'; 127 | when 'Z' => c:= 'Z'; 128 | when 'W' => c:= 'W'; 129 | when 'L' => c:= 'L'; 130 | when 'H' => c:= 'H'; 131 | when '-' => c:= '-'; 132 | end case; 133 | return c; 134 | end chr; 135 | 136 | 137 | 138 | -- converts std_logic into a string (1 to 1) 139 | 140 | function str(sl: std_logic) return string is 141 | variable s: string(1 to 1); 142 | begin 143 | s(1) := chr(sl); 144 | return s; 145 | end str; 146 | 147 | 148 | 149 | -- converts std_logic_vector into a string (binary base) 150 | -- (this also takes care of the fact that the range of 151 | -- a string is natural while a std_logic_vector may 152 | -- have an integer range) 153 | 154 | function str(slv: std_logic_vector) return string is 155 | variable result : string (1 to slv'length); 156 | variable r : integer; 157 | begin 158 | r := 1; 159 | for i in slv'range loop 160 | result(r) := chr(slv(i)); 161 | r := r + 1; 162 | end loop; 163 | return result; 164 | end str; 165 | 166 | 167 | function str(b: boolean) return string is 168 | 169 | begin 170 | if b then 171 | return "true"; 172 | else 173 | return "false"; 174 | end if; 175 | end str; 176 | 177 | 178 | -- converts an integer into a character 179 | -- for 0 to 9 the obvious mapping is used, higher 180 | -- values are mapped to the characters A-Z 181 | -- (this is usefull for systems with base > 10) 182 | -- (adapted from Steve Vogwell's posting in comp.lang.vhdl) 183 | 184 | function chr(int: integer) return character is 185 | variable c: character; 186 | begin 187 | case int is 188 | when 0 => c := '0'; 189 | when 1 => c := '1'; 190 | when 2 => c := '2'; 191 | when 3 => c := '3'; 192 | when 4 => c := '4'; 193 | when 5 => c := '5'; 194 | when 6 => c := '6'; 195 | when 7 => c := '7'; 196 | when 8 => c := '8'; 197 | when 9 => c := '9'; 198 | when 10 => c := 'A'; 199 | when 11 => c := 'B'; 200 | when 12 => c := 'C'; 201 | when 13 => c := 'D'; 202 | when 14 => c := 'E'; 203 | when 15 => c := 'F'; 204 | when 16 => c := 'G'; 205 | when 17 => c := 'H'; 206 | when 18 => c := 'I'; 207 | when 19 => c := 'J'; 208 | when 20 => c := 'K'; 209 | when 21 => c := 'L'; 210 | when 22 => c := 'M'; 211 | when 23 => c := 'N'; 212 | when 24 => c := 'O'; 213 | when 25 => c := 'P'; 214 | when 26 => c := 'Q'; 215 | when 27 => c := 'R'; 216 | when 28 => c := 'S'; 217 | when 29 => c := 'T'; 218 | when 30 => c := 'U'; 219 | when 31 => c := 'V'; 220 | when 32 => c := 'W'; 221 | when 33 => c := 'X'; 222 | when 34 => c := 'Y'; 223 | when 35 => c := 'Z'; 224 | when others => c := '?'; 225 | end case; 226 | return c; 227 | end chr; 228 | 229 | 230 | 231 | -- convert integer to string using specified base 232 | -- (adapted from Steve Vogwell's posting in comp.lang.vhdl) 233 | 234 | function str(int: integer; base: integer) return string is 235 | 236 | variable temp: string(1 to 10); 237 | variable num: integer; 238 | variable abs_int: integer; 239 | variable len: integer := 1; 240 | variable power: integer := 1; 241 | 242 | begin 243 | 244 | -- bug fix for negative numbers 245 | abs_int := abs(int); 246 | 247 | num := abs_int; 248 | 249 | while num >= base loop -- Determine how many 250 | len := len + 1; -- characters required 251 | num := num / base; -- to represent the 252 | end loop ; -- number. 253 | 254 | for i in len downto 1 loop -- Convert the number to 255 | temp(i) := chr(abs_int/power mod base); -- a string starting 256 | power := power * base; -- with the right hand 257 | end loop ; -- side. 258 | 259 | -- return result and add sign if required 260 | if int < 0 then 261 | return '-'& temp(1 to len); 262 | else 263 | return temp(1 to len); 264 | end if; 265 | 266 | end str; 267 | 268 | 269 | -- convert integer to string, using base 10 270 | function str(int: integer) return string is 271 | 272 | begin 273 | 274 | return str(int, 10) ; 275 | 276 | end str; 277 | 278 | 279 | 280 | -- converts a std_logic_vector into a hex string. 281 | function hstr(slv: std_logic_vector) return string is 282 | variable hexlen: integer; 283 | variable longslv : std_logic_vector(67 downto 0) := (others => '0'); 284 | variable hex : string(1 to 16); 285 | variable fourbit : std_logic_vector(3 downto 0); 286 | begin 287 | hexlen := (slv'left+1)/4; 288 | if (slv'left+1) mod 4 /= 0 then 289 | hexlen := hexlen + 1; 290 | end if; 291 | longslv(slv'left downto 0) := slv; 292 | for i in (hexlen -1) downto 0 loop 293 | fourbit := longslv(((i*4)+3) downto (i*4)); 294 | case fourbit is 295 | when "0000" => hex(hexlen -I) := '0'; 296 | when "0001" => hex(hexlen -I) := '1'; 297 | when "0010" => hex(hexlen -I) := '2'; 298 | when "0011" => hex(hexlen -I) := '3'; 299 | when "0100" => hex(hexlen -I) := '4'; 300 | when "0101" => hex(hexlen -I) := '5'; 301 | when "0110" => hex(hexlen -I) := '6'; 302 | when "0111" => hex(hexlen -I) := '7'; 303 | when "1000" => hex(hexlen -I) := '8'; 304 | when "1001" => hex(hexlen -I) := '9'; 305 | when "1010" => hex(hexlen -I) := 'A'; 306 | when "1011" => hex(hexlen -I) := 'B'; 307 | when "1100" => hex(hexlen -I) := 'C'; 308 | when "1101" => hex(hexlen -I) := 'D'; 309 | when "1110" => hex(hexlen -I) := 'E'; 310 | when "1111" => hex(hexlen -I) := 'F'; 311 | when "ZZZZ" => hex(hexlen -I) := 'z'; 312 | when "UUUU" => hex(hexlen -I) := 'u'; 313 | when "XXXX" => hex(hexlen -I) := 'x'; 314 | when others => hex(hexlen -I) := '?'; 315 | end case; 316 | end loop; 317 | return hex(1 to hexlen); 318 | end hstr; 319 | 320 | 321 | 322 | -- functions to manipulate strings 323 | ----------------------------------- 324 | 325 | 326 | -- convert a character to upper case 327 | 328 | function to_upper(c: character) return character is 329 | 330 | variable u: character; 331 | 332 | begin 333 | 334 | case c is 335 | when 'a' => u := 'A'; 336 | when 'b' => u := 'B'; 337 | when 'c' => u := 'C'; 338 | when 'd' => u := 'D'; 339 | when 'e' => u := 'E'; 340 | when 'f' => u := 'F'; 341 | when 'g' => u := 'G'; 342 | when 'h' => u := 'H'; 343 | when 'i' => u := 'I'; 344 | when 'j' => u := 'J'; 345 | when 'k' => u := 'K'; 346 | when 'l' => u := 'L'; 347 | when 'm' => u := 'M'; 348 | when 'n' => u := 'N'; 349 | when 'o' => u := 'O'; 350 | when 'p' => u := 'P'; 351 | when 'q' => u := 'Q'; 352 | when 'r' => u := 'R'; 353 | when 's' => u := 'S'; 354 | when 't' => u := 'T'; 355 | when 'u' => u := 'U'; 356 | when 'v' => u := 'V'; 357 | when 'w' => u := 'W'; 358 | when 'x' => u := 'X'; 359 | when 'y' => u := 'Y'; 360 | when 'z' => u := 'Z'; 361 | when others => u := c; 362 | end case; 363 | 364 | return u; 365 | 366 | end to_upper; 367 | 368 | 369 | -- convert a character to lower case 370 | 371 | function to_lower(c: character) return character is 372 | 373 | variable l: character; 374 | 375 | begin 376 | 377 | case c is 378 | when 'A' => l := 'a'; 379 | when 'B' => l := 'b'; 380 | when 'C' => l := 'c'; 381 | when 'D' => l := 'd'; 382 | when 'E' => l := 'e'; 383 | when 'F' => l := 'f'; 384 | when 'G' => l := 'g'; 385 | when 'H' => l := 'h'; 386 | when 'I' => l := 'i'; 387 | when 'J' => l := 'j'; 388 | when 'K' => l := 'k'; 389 | when 'L' => l := 'l'; 390 | when 'M' => l := 'm'; 391 | when 'N' => l := 'n'; 392 | when 'O' => l := 'o'; 393 | when 'P' => l := 'p'; 394 | when 'Q' => l := 'q'; 395 | when 'R' => l := 'r'; 396 | when 'S' => l := 's'; 397 | when 'T' => l := 't'; 398 | when 'U' => l := 'u'; 399 | when 'V' => l := 'v'; 400 | when 'W' => l := 'w'; 401 | when 'X' => l := 'x'; 402 | when 'Y' => l := 'y'; 403 | when 'Z' => l := 'z'; 404 | when others => l := c; 405 | end case; 406 | 407 | return l; 408 | 409 | end to_lower; 410 | 411 | 412 | 413 | -- convert a string to upper case 414 | 415 | function to_upper(s: string) return string is 416 | 417 | variable uppercase: string (s'range); 418 | 419 | begin 420 | 421 | for i in s'range loop 422 | uppercase(i):= to_upper(s(i)); 423 | end loop; 424 | return uppercase; 425 | 426 | end to_upper; 427 | 428 | 429 | 430 | -- convert a string to lower case 431 | 432 | function to_lower(s: string) return string is 433 | 434 | variable lowercase: string (s'range); 435 | 436 | begin 437 | 438 | for i in s'range loop 439 | lowercase(i):= to_lower(s(i)); 440 | end loop; 441 | return lowercase; 442 | 443 | end to_lower; 444 | 445 | 446 | 447 | -- functions to convert strings into other types 448 | 449 | 450 | -- converts a character into a std_logic 451 | 452 | function to_std_logic(c: character) return std_logic is 453 | variable sl: std_logic; 454 | begin 455 | case c is 456 | when 'U' => 457 | sl := 'U'; 458 | when 'X' => 459 | sl := 'X'; 460 | when '0' => 461 | sl := '0'; 462 | when '1' => 463 | sl := '1'; 464 | when 'Z' => 465 | sl := 'Z'; 466 | when 'W' => 467 | sl := 'W'; 468 | when 'L' => 469 | sl := 'L'; 470 | when 'H' => 471 | sl := 'H'; 472 | when '-' => 473 | sl := '-'; 474 | when others => 475 | sl := 'X'; 476 | end case; 477 | return sl; 478 | end to_std_logic; 479 | 480 | 481 | -- converts a string into std_logic_vector 482 | 483 | function to_std_logic_vector(s: string) return std_logic_vector is 484 | variable slv: std_logic_vector(s'high-s'low downto 0); 485 | variable k: integer; 486 | begin 487 | k := s'high-s'low; 488 | for i in s'range loop 489 | slv(k) := to_std_logic(s(i)); 490 | k := k - 1; 491 | end loop; 492 | return slv; 493 | end to_std_logic_vector; 494 | 495 | 496 | 497 | 498 | 499 | 500 | ---------------- 501 | -- file I/O -- 502 | ---------------- 503 | 504 | 505 | 506 | -- read variable length string from input file 507 | 508 | procedure str_read(file in_file: TEXT; 509 | res_string: out string) is 510 | 511 | variable l: line; 512 | variable c: character; 513 | variable is_string: boolean; 514 | 515 | begin 516 | 517 | readline(in_file, l); 518 | -- clear the contents of the result string 519 | for i in res_string'range loop 520 | res_string(i) := ' '; 521 | end loop; 522 | -- read all characters of the line, up to the length 523 | -- of the results string 524 | for i in res_string'range loop 525 | read(l, c, is_string); 526 | res_string(i) := c; 527 | if not is_string then -- found end of line 528 | exit; 529 | end if; 530 | end loop; 531 | 532 | end str_read; 533 | 534 | 535 | -- print string to a file 536 | procedure print(file out_file: TEXT; 537 | new_string: in string) is 538 | 539 | variable l: line; 540 | 541 | begin 542 | 543 | write(l, new_string); 544 | writeline(out_file, l); 545 | 546 | end print; 547 | 548 | 549 | -- print character to a file and start new line 550 | procedure print(file out_file: TEXT; 551 | char: in character) is 552 | 553 | variable l: line; 554 | 555 | begin 556 | 557 | write(l, char); 558 | writeline(out_file, l); 559 | 560 | end print; 561 | 562 | 563 | 564 | -- appends contents of a string to a file until line feed occurs 565 | -- (LF is considered to be the end of the string) 566 | 567 | procedure str_write(file out_file: TEXT; 568 | new_string: in string) is 569 | begin 570 | 571 | for i in new_string'range loop 572 | print(out_file, new_string(i)); 573 | if new_string(i) = LF then -- end of string 574 | exit; 575 | end if; 576 | end loop; 577 | 578 | end str_write; 579 | 580 | 581 | 582 | 583 | end txt_util; 584 | -------------------------------------------------------------------------------- /src/ucode/light8080.m80: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // LIGHT8080 CORE MICROCODE (V.2 February 12th 2012) 3 | //////////////////////////////////////////////////////////////////////////////// 4 | // NOTE: Except for bug fixing, there's no need to tinker with the microcode. 5 | // Once the microcode table has been generated, this file is is not needed to 6 | // synthesize or use the core. 7 | //////////////////////////////////////////////////////////////////////////////// 8 | // 9 | // ***** FORMAT AND OPERATION: 10 | // 11 | // operation 1 ; operation 2 ; flags 12 | // 13 | // Operation 1 sets up the ALU input registers; operation 2 takes the ALU result 14 | // and writes it back somewhere; and the flags group all other microinstruction 15 | // control signals. 16 | // 17 | // For any given microinstruction, operation 2 takes place in the cycle after 18 | // operation 1. It happens concurrently with the next microinstruction's 19 | // operation 1, so whenever a register is written to in an operation 2 it will 20 | // NOT be available for the next microinstruction. 21 | // 22 | // In operation 1, you may load any one of T1 or T2 from the register bank or 23 | // from DI which is simply the unregistered signal data_in. 24 | // 25 | // In operation 2, you specify the ALU operation and assign the ALU result to 26 | // the register bank or the register DO, which feeds the signal data_out. 27 | // 28 | // You cannot address two different registers from the register bank in 29 | // operations 1 and 2 (see the design notes on this). 30 | // 31 | // *** Some other elements found in the microcode source: 32 | // 33 | // labels: must be in a line by themselves, otherwise work like any assembler. 34 | // __code pragmas: used by assembler to automatically generate the decode table. 35 | // __asm pragmas: not used, but can be handy as a reference. 36 | // 37 | // 38 | // ***** FLAGS: 39 | // 40 | // Note: '1st cycle' and '2nd cycle' denote both cycles of the present 41 | // microinstruction (m.i.); cycle 2 of m.i. N overlaps cycle 1 of m.i. N+1. 42 | // 43 | // #ld_al : Load AL register with register bank output as read by operation 1. 44 | // (used in memory and io access). 45 | // #ld_addr : Load address register (H byte = register bank output as read by 46 | // operation 1, L byte = AL). 47 | // Activate vma signal for 1st cycle. 48 | // #auxcy : Use aux carry instead of regular carry for this operation. 49 | // #setacy : Set aux carry at the start of 1st cycle (used for ++). 50 | // #end : Jump to microinstruction address 3 after the present m.i. 51 | // #ret : Jump to address saved by the last JST or TJSR m.i. 52 | // #rd : Activate rd signal for the 2nd cycle. 53 | // #wr : Activate wr signal for the 2nd cycle. 54 | // #fp_r : This microinstruction updates all PSW flags except for C. 55 | // #fp_c : This microinstruction updates only the C flag in the PSW. 56 | // #fp_rc : This microinstruction updates all the flags in the PSW. 57 | // #clrt1 : Clear T1 at the end of 1st cycle. 58 | // #io : Activate io signal for 1st cycle. 59 | // #ei : Set interrupt enable register. 60 | // #di : Reset interrupt enable register. 61 | // #halt : Jump to microcode address 0x07 without saving return value. 62 | // 63 | //////////////////////////////////////////////////////////////////////////////// 64 | // V.1 November 1st 2007 -- Original version 65 | // V.2 February 12th 2012 -- Fixed CY/AC clear bug with clr_acy flag 66 | //////////////////////////////////////////////////////////////////////////////// 67 | 68 | 69 | // RESET ucode: from 0 to 2, but uinst at address 0 is never executed 70 | __reset 71 | 72 | NOP ; NOP 73 | NOP ; _pl = AND ; // T1 & T2 = 0x00 74 | NOP ; _ph = AND ; // T1 & T2 = 0x00 75 | 76 | // FETCH ucode: from 3 to 6 77 | // (executed in INTA cycles too, with pc increment inhibited to preserve PC) 78 | __fetch 79 | 80 | T1 = _pl ; _pl = ADC ; #ld_al, #auxcy, #setacy 81 | T1 = _ph ; _ph = ADC ; #ld_addr, #rd, #auxcy 82 | NOP ; NOP ; #decode 83 | 84 | // free uinst slot 85 | NOP ; NOP ; 86 | 87 | // HALT ucode: address 7 88 | __halt 89 | NOP ; NOP ; #halt, #end 90 | 91 | 92 | // NOTE: ALU single_operand ops work on T1 93 | // ALU 2-operands work with 'A' on T2 (e.g. SUB == T2 - T1) 94 | 95 | 96 | __code "01dddsss" 97 | __asm MOV {d},{s} 98 | 99 | T1 = {s} ; NOP 100 | NOP ; {d} = T1 ; #end 101 | 102 | 103 | __code "01ddd110" 104 | __asm MOV {d},M 105 | 106 | JSR read_m 107 | NOP ; {d} = T1 ; #end 108 | 109 | 110 | __code "01110sss" 111 | __asm MOV M,{s} 112 | 113 | T1 = {s} ; DO = T1 114 | JSR write_m // does not return 115 | 116 | 117 | __code "00ddd110" 118 | __asm MVI {d},#imm 119 | 120 | JSR read_imm 121 | NOP ; {d} = T1 ; #end 122 | 123 | 124 | __code "00110110" 125 | __asm MVI M,#imm 126 | 127 | JSR read_imm 128 | JSR write_m 129 | 130 | 131 | __code "00pp0001" 132 | __asm LXI [p] 133 | 134 | JSR read_imm 135 | NOP ; {p}1 = T1 136 | JSR read_imm 137 | NOP ; {p}0 = T1 ; #end 138 | 139 | 140 | __code "00111010" 141 | __asm LDA addr 142 | 143 | JSR read_imm_wz 144 | JSR read_wz 145 | NOP ; _a = T1 ; #end 146 | 147 | 148 | __code "00110010" 149 | __asm STA addr 150 | 151 | JSR read_imm_wz 152 | T1 = _a ; DO = T1 ; 153 | JSR write_wz //does not return 154 | 155 | 156 | __code "00101010" 157 | __asm LHLD 158 | 159 | 160 | JSR read_imm_wz 161 | T1 = _z ; _z = ADC ; #ld_al, #auxcy, #setacy // L = (WZ++) 162 | T1 = _w ; _w = ADC ; #ld_addr, #rd, #auxcy 163 | T1 = DI ; _l = T1 164 | JSR read_wz // H = (WZ) 165 | NOP ; _h = T1 ; #end 166 | 167 | 168 | __code "00100010" 169 | __asm SHLD 170 | 171 | JSR read_imm_wz 172 | T1 = _l ; DO = T1 173 | T1 = _z ; _z = ADC ; #ld_al, #auxcy, #setacy 174 | T1 = _w ; _w = ADC ; #ld_addr, #wr, #auxcy 175 | T1 = _h ; DO = T1 176 | JSR write_wz 177 | 178 | 179 | __code "00pp1010" 180 | __asm LDAX [p] 181 | 182 | JSR read_p 183 | NOP ; _a = T1 ; #end 184 | 185 | 186 | __code "00pp0010" 187 | __asm STAX [p] 188 | 189 | T1 = _a ; DO = T1 190 | JSR write_p 191 | 192 | 193 | __code "11101011" 194 | __asm XCHG 195 | 196 | // 16 T cycles vs. 10 for the original 8080... 197 | T1 = _d ; NOP 198 | NOP ; _x = T1 199 | T1 = _e ; NOP 200 | NOP ; _y = T1 201 | T1 = _h ; NOP 202 | NOP ; _d = T1 203 | T1 = _l ; NOP 204 | NOP ; _e = T1 205 | T1 = _x ; NOP 206 | NOP ; _h = T1 207 | T1 = _y ; NOP 208 | NOP ; _l = T1 ; #end 209 | 210 | 211 | __code "11000110" 212 | __asm ADI #imm 213 | 214 | JSR read_imm 215 | T2 = _a ; _a = ADD ; #end, #fp_rc 216 | 217 | __code "11001110" 218 | __asm ACI #imm 219 | 220 | JSR read_imm 221 | T2 = _a ; _a = ADC ; #end, #fp_rc 222 | 223 | __code "11010110" 224 | __asm SUI #imm 225 | 226 | JSR read_imm 227 | T2 = _a ; _a = SUB ; #end, #fp_rc 228 | 229 | __code "11011110" 230 | __asm SBI #imm 231 | 232 | JSR read_imm 233 | T2 = _a ; _a = SBB ; #end, #fp_rc 234 | 235 | 236 | __code "11100110" 237 | __asm ANI #imm 238 | 239 | JSR read_imm 240 | T2 = _a ; _a = AND ; #end, #fp_rc, #clr_acy 241 | 242 | __code "11101110" 243 | __asm XRI #imm 244 | 245 | JSR read_imm 246 | T2 = _a ; _a = XRL ; #end, #fp_rc, #clr_acy 247 | 248 | 249 | __code "11110110" 250 | __asm ORI #imm 251 | 252 | JSR read_imm 253 | T2 = _a ; _a = ORL ; #end, #fp_rc, #clr_acy 254 | 255 | 256 | __code "11111110" 257 | __asm CPI #imm 258 | 259 | JSR read_imm 260 | T2 = _a ; DO = SUB ; #end, #fp_rc 261 | 262 | 263 | 264 | __code "10000sss" 265 | __asm ADD {s} 266 | 267 | T1 = {s} ; NOP 268 | T2 = _a ; _a = ADD ; #end, #fp_rc 269 | 270 | __code "10001sss" 271 | __asm ADC {s} 272 | 273 | T1 = {s} ; NOP 274 | T2 = _a ; _a = ADC ; #end, #fp_rc 275 | 276 | __code "10010sss" 277 | __asm SUB {s} 278 | 279 | T1 = {s} ; NOP 280 | T2 = _a ; _a = SUB ; #end, #fp_rc 281 | 282 | __code "10011sss" 283 | __asm SBB {s} 284 | 285 | T1 = {s} ; NOP 286 | T2 = _a ; _a = SBB ; #end, #fp_rc 287 | 288 | __code "10100sss" 289 | __asm ANA {s} 290 | 291 | T1 = {s} ; NOP 292 | T2 = _a ; _a = AND ; #end, #fp_rc, #clr_acy 293 | 294 | __code "10101sss" 295 | __asm XRA {s} 296 | 297 | T1 = {s} ; NOP 298 | T2 = _a ; _a = XRL ; #end, #fp_rc, #clr_acy 299 | 300 | __code "10110sss" 301 | __asm ORA {s} 302 | 303 | T1 = {s} ; NOP 304 | T2 = _a ; _a = ORL ; #end, #fp_rc, #clr_acy 305 | 306 | __code "10111sss" 307 | __asm CMP {s} 308 | 309 | T1 = {s} ; NOP 310 | T2 = _a ; DO = SUB ; #end, #fp_rc 311 | 312 | 313 | __code "10000110" 314 | __asm ADD M 315 | 316 | JSR read_m 317 | T2 = _a ; _a = ADD ; #end, #fp_rc 318 | 319 | __code "10001110" 320 | __asm ADC M 321 | 322 | JSR read_m 323 | T2 = _a ; _a = ADC ; #end, #fp_rc 324 | 325 | __code "10010110" 326 | __asm SUB M 327 | 328 | JSR read_m 329 | T2 = _a ; _a = SUB ; #end, #fp_rc 330 | 331 | __code "10011110" 332 | __asm SBB M 333 | 334 | JSR read_m 335 | T2 = _a ; _a = SBB ; #end, #fp_rc 336 | 337 | __code "10100110" 338 | __asm ANA M 339 | 340 | JSR read_m 341 | T2 = _a ; _a = AND ; #end, #fp_rc, #clr_acy 342 | 343 | __code "10101110" 344 | __asm XRA M 345 | 346 | JSR read_m 347 | T2 = _a ; _a = XRL ; #end, #fp_rc, #clr_acy 348 | 349 | __code "10110110" 350 | __asm ORA M 351 | 352 | JSR read_m 353 | T2 = _a ; _a = ORL ; #end, #fp_rc, #clr_acy 354 | 355 | 356 | __code "10111110" 357 | __asm CMP M 358 | 359 | JSR read_m 360 | T2 = _a ; DO = SUB ; #end, #fp_rc 361 | 362 | 363 | __code "00ddd100" 364 | __asm INR {d} 365 | 366 | T1 = {d} ; {d} = ADC ; #auxcy, #setacy, #fp_r 367 | NOP ; NOP ; #end // extra line, flag clash 368 | 369 | 370 | __code "00110100" 371 | __asm INR M 372 | 373 | JSR read_m 374 | NOP ; DO = ADC ; #auxcy, #setacy, #fp_r 375 | JSR write_m 376 | 377 | 378 | __code "00ddd101" 379 | __asm DCR {d} 380 | 381 | T2 = {d} ; {d} = SBB ; #auxcy, #setacy, #fp_r 382 | NOP ; NOP ; #end // extra line, flag clash 383 | 384 | 385 | __code "00110101" 386 | __asm DCR M 387 | 388 | JSR read_m // T1 = _x = (HL); but we need it in T2! 389 | NOP ; NOP ; #clrt1 // flag clash 390 | T2 = _x ; DO = SBB ; #auxcy, #setacy, #fp_r 391 | JSR write_m 392 | 393 | 394 | __code "00pp0011" 395 | __asm INX [p] 396 | 397 | T1 = {p}1 ; {p}1 = ADC ; #auxcy, #setacy 398 | T1 = {p}0 ; {p}0 = ADC ; #end, #auxcy 399 | 400 | 401 | __code "00pp1011" 402 | __asm DCX [p] 403 | 404 | T2 = {p}1 ; {p}1 = SBB ; #auxcy, #setacy // T2 because SUB -> T2 - T1 405 | T2 = {p}0 ; {p}0 = SBB ; #end, #auxcy 406 | 407 | 408 | __code "00pp1001" 409 | __asm DAD [p] 410 | 411 | T2 = {p}1 ; NOP 412 | T1 = _l ; _l = ADD ; #fp_c // we need this cy 413 | T2 = {p}0 ; NOP ; 414 | T1 = _h ; _h = ADC ; #end, #fp_c 415 | 416 | 417 | __code "00100111" 418 | __asm DAA 419 | 420 | // DAA result is only valid after the 2nd cycle; 421 | T1 = _a ; DO = DAA ; //DO value ignored 422 | T1 = _a ; _a = DAA ; #end, #fp_rc 423 | 424 | 425 | __code "00000111" 426 | __asm RLC 427 | 428 | T1 = _a ; _a = rla ; #end, #fp_c 429 | 430 | 431 | __code "00001111" 432 | __asm RRC 433 | 434 | T1 = _a ; _a = rra ; #end, #fp_c 435 | 436 | 437 | __code "00010111" 438 | __asm RAL 439 | 440 | T1 = _a ; _a = rlca ; #end, #fp_c 441 | 442 | 443 | __code "00011111" 444 | __asm RAR 445 | 446 | T1 = _a ; _a = rrca ; #end, #fp_c 447 | 448 | 449 | __code "00101111" 450 | __asm CMA 451 | 452 | T1 = _a ; _a = NOT ; #end 453 | 454 | 455 | __code "00111111" 456 | __asm CMC 457 | 458 | NOP ; cpc ; #end, #fp_c 459 | 460 | 461 | __code "00110111" 462 | __asm STC 463 | 464 | NOP ; sec ; #end, #fp_c 465 | 466 | 467 | __code "11000011" 468 | __asm JMP addr 469 | 470 | JSR read_imm_wz 471 | :jmp_addr 472 | T1 = _z ; NOP 473 | NOP ; _pl = T1 474 | T1 = _w ; NOP 475 | NOP ; _ph = T1 ; #end 476 | 477 | 478 | 479 | __code "00000000" 480 | __asm NOP 481 | 482 | NOP ; NOP ; #end 483 | 484 | 485 | __code "11ccc010" 486 | __asm {JZ,JNZ,JC,JNC,JPO,JPE,JP,JM} addr 487 | 488 | JSR read_imm_wz 489 | TJSR jmp_addr // TJSR does the JSR or does #end the instruction. 490 | 491 | 492 | __code "11001101" 493 | __asm CALL addr 494 | 495 | //:call_addr 496 | JSR read_imm_wz 497 | :call_addr //@@ 498 | T1 = _ph ; DO = T1 ; #clrt1 499 | JSR push 500 | T1 = _pl ; DO = T1 ; #clrt1 501 | JSR push 502 | T1 = _z ; NOP 503 | NOP ; _pl = T1 504 | T1 = _w ; NOP 505 | NOP ; _ph = T1 ; #end 506 | 507 | 508 | 509 | __code "11ccc100" 510 | __asm {CZ,CNZ,CC,CNC,CPO,CPE,CP,CM} addr 511 | 512 | JSR read_imm_wz // skip next 2 bytes 513 | TJSR call_addr // TJSR does the JSR or does #end the instruction. 514 | 515 | 516 | __code "11001001" 517 | __asm RET 518 | 519 | :ret 520 | JSR pop 521 | NOP ; _pl = T1 522 | JSR pop 523 | NOP ; _ph = T1 ; #end 524 | 525 | 526 | __code "11ccc000" 527 | __asm {RZ,RNZ,RC,RNC,RPO,RPE,RP,RM} 528 | 529 | 530 | TJSR ret // TJSR does the JSR or does #end the instruction. 531 | 532 | 533 | 534 | __code "11nnn111" 535 | __asm {RST 0h,RST 8h,RST 10h,RST 18h,RST 20h,RST 28h,RST 30h,RST 38h} 536 | 537 | T1 = _ph ; DO = T1 ; #clrt1 538 | JSR push 539 | T1 = _pl ; DO = T1 ; #clrt1 540 | JSR push 541 | NOP ; _pl = rst ; #clrt1 542 | NOP ; _ph = AND ; #end // T1 & T2 = 0, because T2=0 543 | // No extra cycle needed, _ph is not used in the next microinstruction 544 | 545 | __code "11101001" 546 | __asm PCHL 547 | 548 | T1 = _l ; NOP 549 | NOP ; _pl = T1 550 | T1 = _h ; NOP 551 | NOP ; _ph = T1 ; #end 552 | 553 | 554 | __code "11pp0101" //Except for PUSH PSW 555 | __asm PUSH [p] 556 | 557 | T1 = {p}0 ; DO = T1 ; #clrt1 // H first... 558 | JSR push 559 | T1 = {p}1 ; DO = T1 ; #clrt1 // ...L last 560 | JSR push 561 | NOP ; NOP ; #end 562 | 563 | 564 | __code "11110101" 565 | __asm PUSH PSW 566 | 567 | T1 = _a ; DO = T1 ; #clrt1 568 | JSR push 569 | NOP ; DO = PSW ; #clrt1 570 | JSR push 571 | NOP ; NOP ; #end 572 | 573 | 574 | __code "11pp0001" //Except for POP PSW 575 | __asm POP [p] 576 | 577 | JSR pop 578 | NOP ; {p}1 = T1 579 | JSR pop 580 | NOP ; {p}0 = T1 ; #end 581 | 582 | 583 | __code "11110001" 584 | __asm POP PSW 585 | 586 | JSR pop 587 | NOP ; _f = T1 ; #fp_rc //F<-(SP); F f-fs load automatically 588 | JSR pop 589 | NOP ; _a = T1 ; #end 590 | 591 | 592 | __code "11100011" 593 | __asm XTHL 594 | 595 | JSR pop 596 | NOP ; _z = T1 597 | JSR pop 598 | NOP ; _w = T1 599 | T1 = _h ; DO = T1 ; #clrt1 600 | JSR push 601 | T1 = _l ; DO = T1 ; #clrt1 602 | JSR push 603 | T1 = _z ; NOP 604 | NOP ; _l = T1 605 | T1 = _w ; NOP 606 | NOP ; _h = T1 ; #end 607 | 608 | 609 | __code "11111001" 610 | __asm SPHL 611 | 612 | T1 = _l ; NOP 613 | NOP ; _sl = T1 614 | T1 = _h ; NOP 615 | NOP ; _sh = T1 ; #end 616 | 617 | 618 | __code "11111011" 619 | __asm EI 620 | 621 | NOP ; NOP ; #ei, #end 622 | 623 | 624 | __code "11110011" 625 | __asm DI 626 | 627 | NOP ; NOP ; #di, #end 628 | 629 | 630 | __code "11011011" 631 | __asm IN port 632 | 633 | NOP ; _w = T1 // _w = 0 634 | JSR read_imm // T1 = port 635 | NOP ; _z = T1 // #ld_al reads from mux... 636 | NOP ; NOP 637 | T1 = _z ; NOP ; #ld_al 638 | T1 = _w ; NOP ; #ld_addr, #rd, #io 639 | T1 = DI ; _a = T1 ; #end 640 | 641 | 642 | // Can be reduced to 11 states by removing 1st uinst 643 | // Then, _b might be put on high addr byte as in the original... 644 | __code "11010011" 645 | __asm OUT port 646 | 647 | 648 | NOP ; _w = T1 // _w = 0, put on high byte of io address 649 | JSR read_imm // T1 = port 650 | NOP ; _z = T1 // #ld_al reads from mux... 651 | T1 = _a ; DO = T1 652 | T1 = _z ; NOP ; #ld_al 653 | T1 = _w ; NOP ; #ld_addr, #wr, #io 654 | NOP ; NOP ; #end 655 | 656 | 657 | __code "01110110" 658 | __asm HLT 659 | //TODO doc: #halt has to be in the same cycle as #end 660 | NOP ; NOP ; #halt, #end 661 | 662 | 663 | 664 | 665 | //******************************************** 666 | 667 | // T1 = (HL) 668 | 669 | :read_m 670 | 671 | T1 = _l ; NOP ; #ld_al 672 | T1 = _h ; NOP ; #ld_addr, #rd 673 | T1 = DI ; _x = T1 ; #ret 674 | 675 | // (HL) = DO, does not return 676 | // TODO extra uinst is for wait state, which is not implemented 677 | 678 | :write_m 679 | 680 | T1 = _l ; NOP ; #ld_al 681 | T1 = _h ; NOP ; #ld_addr, #wr 682 | NOP ; NOP ; #end 683 | 684 | 685 | // T1 = (PC++), DO = T1 686 | // T2 must be 0 on entry 687 | :read_imm 688 | 689 | T1 = _pl ; _pl = ADC ; #ld_al, #auxcy, #setacy 690 | T1 = _ph ; _ph = ADC ; #ld_addr, #rd, #auxcy 691 | T1 = DI ; DO = T1 ; #ret 692 | 693 | 694 | // T1 = (WZ) 695 | 696 | :read_wz 697 | 698 | T1 = _z ; NOP ; #ld_al 699 | T1 = _w ; NOP ; #ld_addr, #rd 700 | T1 = DI ; NOP ; #ret 701 | 702 | 703 | // (WZ) = DO, does not return 704 | // TODO extra uinst is for wait state, which is not implemented 705 | 706 | :write_wz 707 | 708 | T1 = _z ; NOP ; #ld_al 709 | T1 = _w ; NOP ; #ld_addr, #wr 710 | NOP ; NOP ; #end 711 | 712 | // T1 = (RP) 713 | 714 | :read_p 715 | 716 | T1 = {p}1 ; NOP ; #ld_al 717 | T1 = {p}0 ; NOP ; #ld_addr, #rd 718 | T1 = DI ; NOP ; #ret 719 | 720 | 721 | // (RP) = DO, does not return 722 | // TODO extra uinst is for wait state, which is not implemented 723 | 724 | :write_p 725 | 726 | T1 = {p}1 ; NOP ; #ld_al 727 | T1 = {p}0 ; NOP ; #ld_addr, #wr 728 | NOP ; NOP ; #end 729 | 730 | // WZ = imm16 731 | 732 | :read_imm_wz 733 | 734 | T1 = _pl ; _pl = ADC ; #ld_al, #auxcy, #setacy 735 | T1 = _ph ; _ph = ADC ; #ld_addr, #rd, #auxcy 736 | T1 = DI ; _z = T1 737 | T1 = _pl ; _pl = ADC ; #ld_al, #auxcy, #setacy 738 | T1 = _ph ; _ph = ADC ; #ld_addr, #rd, #auxcy 739 | T1 = DI ; _w = T1 ; #ret 740 | 741 | // push DO 742 | // no wait cycle! 743 | 744 | :push 745 | T2 = _sl ; _sl = SBB ; #auxcy, #setacy 746 | T2 = _sh ; _sh = SBB ; #auxcy 747 | T1 = _sl ; NOP ; #ld_al 748 | T1 = _sh ; NOP ; #ld_addr, #wr 749 | NOP ; NOP ; #ret // extra line, flag clash 750 | 751 | 752 | // POP T1 753 | 754 | :pop 755 | T1 = _sl ; _sl = ADC ; #ld_al, #auxcy, #setacy 756 | T1 = _sh ; _sh = ADC ; #ld_addr, #rd, #auxcy 757 | T1 = DI ; NOP ; #ret // extra line, flag clash 758 | 759 | 760 | // End of file -------------------------------------------------------------------------------- /syn/de1_quartus2/build.tcl: -------------------------------------------------------------------------------- 1 | # Build script for Quartus 2. 2 | # Run this script with quartus_sh -t 3 | 4 | ##################################################################################### 5 | # Command line arguments. 6 | ##################################################################################### 7 | 8 | if {$argc < 1} { 9 | puts "Missing command line argument." 10 | puts "Usage: $argv0 " 11 | exit 1 12 | } 13 | set PROJECT_ROOT [lindex $argv 0] 14 | 15 | 16 | ##################################################################################### 17 | # Project configuration. 18 | ##################################################################################### 19 | 20 | set PROJECT_NAME "de1_demo" 21 | set PROJECT_TOP "de1_top" 22 | set RTL_DIR "$PROJECT_ROOT/src/vhdl/rtl" 23 | set BOARD_DIR "$PROJECT_ROOT/boards/de1" 24 | set OBJ_CODE_DIR "$PROJECT_ROOT/src/sw/hello" 25 | 26 | ##################################################################################### 27 | # Create project, then add source files and pin assignments. 28 | ##################################################################################### 29 | 30 | # Load whatever Altera packages are needed by the flow commands below. 31 | load_package flow 32 | 33 | # Create the project. 34 | project_new $PROJECT_NAME -overwrite 35 | 36 | # Add all the source files. Order counts. 37 | set_global_assignment -name VHDL_FILE $RTL_DIR/mcu/mcu80_pkg.vhdl 38 | set_global_assignment -name VHDL_FILE $OBJ_CODE_DIR/obj_code_pkg.vhdl 39 | set_global_assignment -name VHDL_FILE $RTL_DIR/mcu/mcu80_uart.vhdl 40 | set_global_assignment -name VHDL_FILE $RTL_DIR/mcu/mcu80_irq.vhdl 41 | set_global_assignment -name VHDL_FILE $RTL_DIR/mcu/mcu80.vhdl 42 | set_global_assignment -name VHDL_FILE $RTL_DIR/light8080_ucode_pkg.vhdl 43 | set_global_assignment -name VHDL_FILE $RTL_DIR/light8080.vhdl 44 | set_global_assignment -name VHDL_FILE $BOARD_DIR/$PROJECT_TOP.vhdl 45 | 46 | # Prepare project to target Terasic's DE1 board. 47 | set_global_assignment -name FAMILY "Cyclone II" 48 | set_global_assignment -name DEVICE EP2C20F484C7 49 | set_global_assignment -name TOP_LEVEL_ENTITY $PROJECT_TOP 50 | # We're gonna use one of these pins as regular I/O so let the synth tool know. 51 | set_global_assignment -name CYCLONEII_RESERVE_NCEO_AFTER_CONFIGURATION "USE AS REGULAR IO" 52 | set_global_assignment -name RESERVE_ASDO_AFTER_CONFIGURATION "USE AS REGULAR IO" 53 | 54 | #------------------------------------------------------------------------------------ 55 | # Pin assignments: placement & I/O standard. 56 | #------------------------------------------------------------------------------------ 57 | 58 | set_location_assignment PIN_T21 -to buttons[3] 59 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to buttons[3] 60 | set_location_assignment PIN_T22 -to buttons[2] 61 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to buttons[2] 62 | set_location_assignment PIN_R21 -to buttons[1] 63 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to buttons[1] 64 | set_location_assignment PIN_R22 -to buttons[0] 65 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to buttons[0] 66 | set_location_assignment PIN_R13 -to flash_addr[21] 67 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_addr[21] 68 | set_location_assignment PIN_U13 -to flash_addr[20] 69 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_addr[20] 70 | set_location_assignment PIN_V14 -to flash_addr[19] 71 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_addr[19] 72 | set_location_assignment PIN_U14 -to flash_addr[18] 73 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_addr[18] 74 | set_location_assignment PIN_AA20 -to flash_addr[17] 75 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_addr[17] 76 | set_location_assignment PIN_AB12 -to flash_addr[16] 77 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_addr[16] 78 | set_location_assignment PIN_AA12 -to flash_addr[15] 79 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_addr[15] 80 | set_location_assignment PIN_AB13 -to flash_addr[14] 81 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_addr[14] 82 | set_location_assignment PIN_AA13 -to flash_addr[13] 83 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_addr[13] 84 | set_location_assignment PIN_AB14 -to flash_addr[12] 85 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_addr[12] 86 | set_location_assignment PIN_T12 -to flash_addr[11] 87 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_addr[11] 88 | set_location_assignment PIN_R12 -to flash_addr[10] 89 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_addr[10] 90 | set_location_assignment PIN_Y13 -to flash_addr[9] 91 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_addr[9] 92 | set_location_assignment PIN_R14 -to flash_addr[8] 93 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_addr[8] 94 | set_location_assignment PIN_W15 -to flash_addr[7] 95 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_addr[7] 96 | set_location_assignment PIN_V15 -to flash_addr[6] 97 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_addr[6] 98 | set_location_assignment PIN_U15 -to flash_addr[5] 99 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_addr[5] 100 | set_location_assignment PIN_T15 -to flash_addr[4] 101 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_addr[4] 102 | set_location_assignment PIN_R15 -to flash_addr[3] 103 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_addr[3] 104 | set_location_assignment PIN_Y16 -to flash_addr[2] 105 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_addr[2] 106 | set_location_assignment PIN_AA14 -to flash_addr[1] 107 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_addr[1] 108 | set_location_assignment PIN_AB20 -to flash_addr[0] 109 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_addr[0] 110 | set_location_assignment PIN_AA19 -to flash_data[7] 111 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_data[7] 112 | set_location_assignment PIN_AB19 -to flash_data[6] 113 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_data[6] 114 | set_location_assignment PIN_AA18 -to flash_data[5] 115 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_data[5] 116 | set_location_assignment PIN_AB18 -to flash_data[4] 117 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_data[4] 118 | set_location_assignment PIN_AA17 -to flash_data[3] 119 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_data[3] 120 | set_location_assignment PIN_AB17 -to flash_data[2] 121 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_data[2] 122 | set_location_assignment PIN_AA16 -to flash_data[1] 123 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_data[1] 124 | set_location_assignment PIN_AB16 -to flash_data[0] 125 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_data[0] 126 | set_location_assignment PIN_AA15 -to flash_oe_n 127 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_oe_n 128 | set_location_assignment PIN_W14 -to flash_reset_n 129 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_reset_n 130 | set_location_assignment PIN_Y14 -to flash_we_n 131 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to flash_we_n 132 | set_location_assignment PIN_Y21 -to green_leds[7] 133 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to green_leds[7] 134 | set_location_assignment PIN_Y22 -to green_leds[6] 135 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to green_leds[6] 136 | set_location_assignment PIN_W21 -to green_leds[5] 137 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to green_leds[5] 138 | set_location_assignment PIN_W22 -to green_leds[4] 139 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to green_leds[4] 140 | set_location_assignment PIN_V21 -to green_leds[3] 141 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to green_leds[3] 142 | set_location_assignment PIN_V22 -to green_leds[2] 143 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to green_leds[2] 144 | set_location_assignment PIN_U21 -to green_leds[1] 145 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to green_leds[1] 146 | set_location_assignment PIN_U22 -to green_leds[0] 147 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to green_leds[0] 148 | set_location_assignment PIN_J2 -to hex0[0] 149 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to hex0[0] 150 | set_location_assignment PIN_J1 -to hex0[1] 151 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to hex0[1] 152 | set_location_assignment PIN_H2 -to hex0[2] 153 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to hex0[2] 154 | set_location_assignment PIN_H1 -to hex0[3] 155 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to hex0[3] 156 | set_location_assignment PIN_F2 -to hex0[4] 157 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to hex0[4] 158 | set_location_assignment PIN_F1 -to hex0[5] 159 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to hex0[5] 160 | set_location_assignment PIN_E2 -to hex0[6] 161 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to hex0[6] 162 | set_location_assignment PIN_E1 -to hex1[0] 163 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to hex1[0] 164 | set_location_assignment PIN_H6 -to hex1[1] 165 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to hex1[1] 166 | set_location_assignment PIN_H5 -to hex1[2] 167 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to hex1[2] 168 | set_location_assignment PIN_H4 -to hex1[3] 169 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to hex1[3] 170 | set_location_assignment PIN_G3 -to hex1[4] 171 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to hex1[4] 172 | set_location_assignment PIN_D2 -to hex1[5] 173 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to hex1[5] 174 | set_location_assignment PIN_D1 -to hex1[6] 175 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to hex1[6] 176 | set_location_assignment PIN_G5 -to hex2[0] 177 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to hex2[0] 178 | set_location_assignment PIN_G6 -to hex2[1] 179 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to hex2[1] 180 | set_location_assignment PIN_C2 -to hex2[2] 181 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to hex2[2] 182 | set_location_assignment PIN_C1 -to hex2[3] 183 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to hex2[3] 184 | set_location_assignment PIN_E3 -to hex2[4] 185 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to hex2[4] 186 | set_location_assignment PIN_E4 -to hex2[5] 187 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to hex2[5] 188 | set_location_assignment PIN_D3 -to hex2[6] 189 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to hex2[6] 190 | set_location_assignment PIN_F4 -to hex3[0] 191 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to hex3[0] 192 | set_location_assignment PIN_D5 -to hex3[1] 193 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to hex3[1] 194 | set_location_assignment PIN_D6 -to hex3[2] 195 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to hex3[2] 196 | set_location_assignment PIN_J4 -to hex3[3] 197 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to hex3[3] 198 | set_location_assignment PIN_L8 -to hex3[4] 199 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to hex3[4] 200 | set_location_assignment PIN_F3 -to hex3[5] 201 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to hex3[5] 202 | set_location_assignment PIN_D4 -to hex3[6] 203 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to hex3[6] 204 | set_location_assignment PIN_R17 -to red_leds[9] 205 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to red_leds[9] 206 | set_location_assignment PIN_R18 -to red_leds[8] 207 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to red_leds[8] 208 | set_location_assignment PIN_U18 -to red_leds[7] 209 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to red_leds[7] 210 | set_location_assignment PIN_Y18 -to red_leds[6] 211 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to red_leds[6] 212 | set_location_assignment PIN_V19 -to red_leds[5] 213 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to red_leds[5] 214 | set_location_assignment PIN_T18 -to red_leds[4] 215 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to red_leds[4] 216 | set_location_assignment PIN_Y19 -to red_leds[3] 217 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to red_leds[3] 218 | set_location_assignment PIN_U19 -to red_leds[2] 219 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to red_leds[2] 220 | set_location_assignment PIN_R19 -to red_leds[1] 221 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to red_leds[1] 222 | set_location_assignment PIN_R20 -to red_leds[0] 223 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to red_leds[0] 224 | set_location_assignment PIN_F14 -to rxd 225 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to rxd 226 | set_location_assignment PIN_V20 -to sd_clk 227 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sd_clk 228 | set_location_assignment PIN_Y20 -to sd_cmd 229 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sd_cmd 230 | set_location_assignment PIN_U20 -to sd_cs 231 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sd_cs 232 | set_location_assignment PIN_W20 -to sd_data 233 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sd_data 234 | set_location_assignment PIN_Y5 -to sram_addr[17] 235 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_addr[17] 236 | set_location_assignment PIN_Y6 -to sram_addr[16] 237 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_addr[16] 238 | set_location_assignment PIN_T7 -to sram_addr[15] 239 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_addr[15] 240 | set_location_assignment PIN_R10 -to sram_addr[14] 241 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_addr[14] 242 | set_location_assignment PIN_U10 -to sram_addr[13] 243 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_addr[13] 244 | set_location_assignment PIN_Y10 -to sram_addr[12] 245 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_addr[12] 246 | set_location_assignment PIN_T11 -to sram_addr[11] 247 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_addr[11] 248 | set_location_assignment PIN_R11 -to sram_addr[10] 249 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_addr[10] 250 | set_location_assignment PIN_W11 -to sram_addr[9] 251 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_addr[9] 252 | set_location_assignment PIN_V11 -to sram_addr[8] 253 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_addr[8] 254 | set_location_assignment PIN_AB11 -to sram_addr[7] 255 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_addr[7] 256 | set_location_assignment PIN_AA11 -to sram_addr[6] 257 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_addr[6] 258 | set_location_assignment PIN_AB10 -to sram_addr[5] 259 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_addr[5] 260 | set_location_assignment PIN_AA5 -to sram_addr[4] 261 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_addr[4] 262 | set_location_assignment PIN_AB4 -to sram_addr[3] 263 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_addr[3] 264 | set_location_assignment PIN_AA4 -to sram_addr[2] 265 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_addr[2] 266 | set_location_assignment PIN_AB3 -to sram_addr[1] 267 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_addr[1] 268 | set_location_assignment PIN_AA3 -to sram_addr[0] 269 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_addr[0] 270 | set_location_assignment PIN_AB5 -to sram_ce_n 271 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_ce_n 272 | set_location_assignment PIN_U8 -to sram_data[15] 273 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_data[15] 274 | set_location_assignment PIN_V8 -to sram_data[14] 275 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_data[14] 276 | set_location_assignment PIN_W8 -to sram_data[13] 277 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_data[13] 278 | set_location_assignment PIN_R9 -to sram_data[12] 279 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_data[12] 280 | set_location_assignment PIN_U9 -to sram_data[11] 281 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_data[11] 282 | set_location_assignment PIN_V9 -to sram_data[10] 283 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_data[10] 284 | set_location_assignment PIN_W9 -to sram_data[9] 285 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_data[9] 286 | set_location_assignment PIN_Y9 -to sram_data[8] 287 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_data[8] 288 | set_location_assignment PIN_AB9 -to sram_data[7] 289 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_data[7] 290 | set_location_assignment PIN_AA9 -to sram_data[6] 291 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_data[6] 292 | set_location_assignment PIN_AB8 -to sram_data[5] 293 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_data[5] 294 | set_location_assignment PIN_AA8 -to sram_data[4] 295 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_data[4] 296 | set_location_assignment PIN_AB7 -to sram_data[3] 297 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_data[3] 298 | set_location_assignment PIN_AA7 -to sram_data[2] 299 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_data[2] 300 | set_location_assignment PIN_AB6 -to sram_data[1] 301 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_data[1] 302 | set_location_assignment PIN_AA6 -to sram_data[0] 303 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_data[0] 304 | set_location_assignment PIN_Y7 -to sram_lb_n 305 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_lb_n 306 | set_location_assignment PIN_T8 -to sram_oe_n 307 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_oe_n 308 | set_location_assignment PIN_W7 -to sram_ub_n 309 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_ub_n 310 | set_location_assignment PIN_AA10 -to sram_we_n 311 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to sram_we_n 312 | set_location_assignment PIN_L2 -to switches[9] 313 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to switches[9] 314 | set_location_assignment PIN_M1 -to switches[8] 315 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to switches[8] 316 | set_location_assignment PIN_M2 -to switches[7] 317 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to switches[7] 318 | set_location_assignment PIN_U11 -to switches[6] 319 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to switches[6] 320 | set_location_assignment PIN_U12 -to switches[5] 321 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to switches[5] 322 | set_location_assignment PIN_W12 -to switches[4] 323 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to switches[4] 324 | set_location_assignment PIN_V12 -to switches[3] 325 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to switches[3] 326 | set_location_assignment PIN_M22 -to switches[2] 327 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to switches[2] 328 | set_location_assignment PIN_L21 -to switches[1] 329 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to switches[1] 330 | set_location_assignment PIN_L22 -to switches[0] 331 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to switches[0] 332 | set_location_assignment PIN_G12 -to txd 333 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to txd 334 | set_location_assignment PIN_L1 -to clk_50MHz 335 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to clk_50MHz 336 | 337 | 338 | ##################################################################################### 339 | # Run the flow. 340 | ##################################################################################### 341 | 342 | # Synthesize, fit, assemble a programming file, and run timing analysis. 343 | puts "#### Analysis & Synthesis ######################################################" 344 | execute_module -tool map 345 | puts "#### Fitter ####################################################################" 346 | execute_module -tool fit 347 | puts "#### Assembler #################################################################" 348 | execute_module -tool asm 349 | puts "#### Timing Analyzer ###########################################################" 350 | execute_module -tool sta -args --sdc=constraints.sdc 351 | 352 | # Close the project 353 | project_close 354 | -------------------------------------------------------------------------------- /src/vhdl/rtl/mcu/mcu80_uart.vhdl: -------------------------------------------------------------------------------- 1 | --############################################################################## 2 | -- mcu80_uart.vhdl -- Basic, hardwired RS232 UART. 3 | -- 4 | -- Most operational parameters are hardcoded: 8 bit words, no parity, 1 stop 5 | -- bit. The only parameter that can be configured in run time is the baud rate. 6 | -- 7 | -- The receiver logic is a simplified copy of the 8051 UART. The bit period is 8 | -- split in 16 sampling periods, and 3 samples are taken at the center of each 9 | -- bit period. The bit value is decided by majority. The receiver logic has some 10 | -- error recovery capability that should make this core reliable enough for 11 | -- actual application use -- yet, the core does not have a formal test bench. 12 | -- 13 | -- See usage notes below. 14 | -- 15 | -------------------------------------------------------------------------------- 16 | -- Please see the LICENSE file in the project root for license matters. 17 | --############################################################################## 18 | 19 | library ieee; 20 | use ieee.std_logic_1164.all; 21 | use ieee.numeric_std.all; 22 | 23 | 24 | -------------------------------------------------------------------------------- 25 | -- UART programmer model 26 | -------------------------------------------------------------------------------- 27 | -- 28 | -- The UART has a number of configuration registers addressable with input 29 | -- signal addr_i: 30 | -- 31 | -- [00] => Data buffer, both transmission and reception. 32 | -- [01] => Status/control register (r/w). 33 | -- [10] => Bit period register, low byte. 34 | -- [11] => Bit period register, high byte. 35 | -- 36 | -- 37 | -- Data buffers: 38 | ---------------- 39 | -- 40 | -- The same address [00b] is used for both the receive buffer and the 41 | -- transmision buffer. 42 | -- 43 | -- Writing to the data buffer when flag TxRdy is high will trigger a 44 | -- transmission and clear flag TxRdy. 45 | -- Writing to the data buffer when flag TxRdy is clear will have no effect. 46 | -- 47 | -- Reading the data register when flag RxRdy is high will return the last 48 | -- received data byte, and will clear flag RxRdy but NOT RxIrq. 49 | -- Reading the register when flag RxRdy is clear will return indeterminate data, 50 | -- which in practice will usually be the last byte received. 51 | -- 52 | -- Interrupts: 53 | -------------- 54 | -- 55 | -- The core has two interrupt sources tied to a single external irq line. The 56 | -- sources are these: 57 | -- 58 | -- -# Receiver interrupt: Raised when the stop bit is sampled and determined 59 | -- to be valid (about the middle of the bit period). 60 | -- If the stop bit is not valid (not high) then the interrupt is not 61 | -- triggered. If a start bit is determined to be spurious (i.e. the falling 62 | -- edge is detected but the bit value when sampled is not 0) then the 63 | -- interrupt is not triggered. 64 | -- This interrupt sets flag RxIrw in the status register. 65 | -- -# Transmitter interrupt: Raised at the end of the transmission of the stop 66 | -- bit. 67 | -- This interrupt sets flag TxIrq in the status register 1 clock cycle after 68 | -- the interrupt is raised. 69 | -- 70 | -- The core does not have any interrupt enable mask. If any interrupt source 71 | -- triggers, the output irq_o is asserted for one cycle. This is all the extent 72 | -- of the interrupt processing done by this module: this UART needs a separate 73 | -- interrupt controller to interface the light8080 core. 74 | -- 75 | -- Error detection: 76 | ------------------- 77 | -- 78 | -- The core is capable of detecting and recovering from these error conditions: 79 | -- 80 | -- -# When a start bit is determined to be spurious (i.e. the falling edge is 81 | -- detected but the bit value when sampled is not 0) then the core returns to 82 | -- its idle state (waiting for a new start bit). 83 | -- -# If a stop bit is determined to be invalid (not 1 when sampled), the 84 | -- reception interrupt is not triggered and the received byte is discarded. 85 | -- -# When the 3 samples taken from the center of a bit period are not equal, 86 | -- the bit value is decided by majority. 87 | -- 88 | -- In none of the 3 cases does the core raise any error flag. It would be very 89 | -- easy to include those flags in the core, but it would take a lot more time 90 | -- to test them minimally and that's why they haven't been included. 91 | -- 92 | -- Status register flags: 93 | ------------------------- 94 | -- 95 | -- 7 6 5 4 3 2 1 0 96 | -- +-------+-------+-------+-------+-------+-------+-------+-------+ 97 | -- | 0 | 0 | RxIrq | TxIrq | 0 | 0 | RxRdy | TxRdy | 98 | -- +-------+-------+-------+-------+-------+-------+-------+-------+ 99 | -- h h W1C W1C h h r r 100 | -- 101 | -- Bits marked 'h' are hardwired and can't be modified. 102 | -- Bits marked 'r' are read only; they are set and clear by the core. 103 | -- Bits marked W1C ('Write 1 Clear') are set by the core when an interrupt 104 | -- has been triggered and must be cleared by the software by writing a '1'. 105 | -- 106 | -- -# Status bit TxRdy is high when there isn't any transmission in progress. 107 | -- It is cleared when data is written to the transmission buffer and is 108 | -- raised at the same time the transmission interrupt is triggered. 109 | -- -# Status bit RxRdy is raised at the same time the receive interrupt is 110 | -- triggered and is cleared when the data register is read. 111 | -- -# Status bit TxIrq is raised when the transmission interrupt is triggered 112 | -- and is cleared when a 1 is written to it. 113 | -- -# Status bit RxIrq is raised when the reception interrupt is triggered 114 | -- and is cleared when a 1 is written to it. 115 | -- 116 | -- When writing to the status/control registers, only flags TxIrq and RxIrq are 117 | -- affected, and only when writing a '1' as explained above. All other flags 118 | -- are read-only. 119 | -- 120 | -- Baud rate configuration: 121 | --------------------------- 122 | -- 123 | -- The baud rate is determined by the value of 14-bit register 'bit_period_reg'. 124 | -- This register holds the length of the bit period in clock cycles and its 125 | -- value may be hardcoded or configured at run time. 126 | -- 127 | -- When generic HARDWIRED is true, bit_period_reg is hardwired with a value 128 | -- computed from the value of generic BAUD_RATE. The bit period computation 129 | -- needs to know the master clock rate, which should be given in generic 130 | -- CLOCK_RATE. 131 | -- Writes to the baud registers when HARDWIRED is true will be ignored. 132 | -- 133 | -- When generic HARDWIRED is false, generics BAUD_RATE and CLOCK_RATE determine 134 | -- the reset value of bit_period_reg, but the register can be changed at run 135 | -- time by writing at addresses [10b] and [11b], which access the low and high 136 | -- bytes of the register, respectively. 137 | -- Reading from those register addresses returns the value of the status 138 | -- register (a LUT saving measure) so the registers are effectively write-only. 139 | -- 140 | -------------------------------------------------------------------------------- 141 | -- Core interface signals: 142 | -- 143 | -- clk_i: Clock input, active rising edge. 144 | -- reset_i: Synchronous reset. 145 | -- txd_o: TxD UART output. 146 | -- rxd_i: RxD UART input -- synchronization logic included. 147 | -- irq_o: Interrupt output, asserted for 1 cycle when triggered. 148 | -- data_i: Data bus, input. 149 | -- data_o: Data bus, output. 150 | -- addr_i: Register selection address (see above). 151 | -- wr_i: Write enable input. 152 | -- rd_i: Read enable input. 153 | -- ce_i: Chip enable, must be active at the same time as wr_i or rd_i. 154 | -- 155 | -- 156 | -- A detailed explanation of the interface timing will not be given. The core 157 | -- reads and writes like a synchronous memory. There's usage examples in other 158 | -- project files. 159 | -------------------------------------------------------------------------------- 160 | 161 | entity mcu80_uart is 162 | generic ( 163 | HARDWIRED : boolean := true; -- Baud rate hardwired to constant value 164 | BAUD_RATE : integer := 19200; -- Default (or hardwired) baud rate 165 | CLOCK_FREQ : integer := 50E6 -- Clock rate 166 | ); 167 | port ( 168 | rxd_i : in std_logic; 169 | txd_o : out std_logic; 170 | 171 | irq_o : out std_logic; 172 | 173 | data_i : in std_logic_vector(7 downto 0); 174 | data_o : out std_logic_vector(7 downto 0); 175 | 176 | addr_i : in std_logic_vector(1 downto 0); 177 | wr_i : in std_logic; 178 | rd_i : in std_logic; 179 | ce_i : in std_logic; 180 | 181 | clk_i : in std_logic; 182 | reset_i : in std_logic 183 | ); 184 | end mcu80_uart; 185 | 186 | architecture hardwired of mcu80_uart is 187 | 188 | -- Bit period expressed in master clock cycles 189 | constant DEFAULT_BIT_PERIOD : integer := (CLOCK_FREQ / BAUD_RATE); 190 | 191 | -- Bit sampling period is 1/16 of the baud rate. 192 | constant DEFAULT_SAMPLING_PERIOD : integer := DEFAULT_BIT_PERIOD / 16; 193 | 194 | 195 | 196 | --############################################################################## 197 | 198 | -- Common signals 199 | 200 | signal reset : std_logic; 201 | signal clk : std_logic; 202 | 203 | 204 | signal bit_period_reg : unsigned(13 downto 0); 205 | signal sampling_period : unsigned(9 downto 0); 206 | 207 | 208 | -- Interrupt & status register signals 209 | 210 | signal tx_irq_flag : std_logic; 211 | signal rx_irq_flag : std_logic; 212 | signal load_stat_reg : std_logic; 213 | signal load_tx_reg : std_logic; 214 | 215 | -- Receiver signals 216 | signal rxd_q : std_logic; 217 | signal tick_ctr : unsigned(3 downto 0); 218 | signal state : unsigned(3 downto 0); 219 | signal next_state : unsigned(3 downto 0); 220 | signal start_bit_detected : std_logic; 221 | signal reset_tick_ctr : std_logic; 222 | signal stop_bit_sampled : std_logic; 223 | signal load_rx_buffer : std_logic; 224 | signal stop_error : std_logic; 225 | signal samples : std_logic_vector(2 downto 0); 226 | signal sampled_bit : std_logic; 227 | signal do_shift : std_logic; 228 | signal rx_buffer : std_logic_vector(7 downto 0); 229 | signal rx_shift_reg : std_logic_vector(9 downto 0); 230 | signal tick_ctr_enable : std_logic; 231 | signal tick_baud_ctr : unsigned(10 downto 0); 232 | 233 | signal rx_rdy_flag : std_logic; 234 | signal rx_irq : std_logic; 235 | signal set_rx_rdy_flag : std_logic; 236 | signal rxd : std_logic; 237 | 238 | signal read_rx : std_logic; 239 | signal status : std_logic_vector(7 downto 0); 240 | 241 | -- Transmitter signals 242 | 243 | signal tx_counter : unsigned(13 downto 0); 244 | signal tx_data : std_logic_vector(10 downto 0); 245 | signal tx_ctr_bit : unsigned(3 downto 0); 246 | signal tx_busy : std_logic; 247 | signal tx_irq : std_logic; 248 | 249 | 250 | 251 | begin 252 | 253 | -- Rename the most commonly used inputs to get rid of the i/o suffix 254 | clk <= clk_i; 255 | reset <= reset_i; 256 | rxd <= rxd_i; 257 | 258 | 259 | -- Serial port status byte -- only 2 status flags 260 | status <= 261 | "00" & rx_irq_flag & tx_irq_flag & -- Interrupt flags 262 | "00" & rx_rdy_flag & (not tx_busy); -- State flags 263 | 264 | -- Read register multiplexor 265 | with addr_i select data_o <= 266 | rx_buffer when "00", 267 | status when others; 268 | 269 | 270 | load_tx_reg <= '1' when wr_i = '1' and ce_i = '1' and addr_i = "00" else '0'; 271 | load_stat_reg <= '1' when wr_i = '1' and ce_i = '1' and addr_i = "01" else '0'; 272 | read_rx <= '1' when rd_i = '1' and ce_i = '1' else '0'; 273 | 274 | rx_irq <= set_rx_rdy_flag; 275 | 276 | irq_o <= rx_irq or tx_irq; 277 | 278 | interrupt_flags: 279 | process(clk) 280 | begin 281 | if clk'event and clk='1' then 282 | if reset = '1' then 283 | rx_irq_flag <= '0'; 284 | tx_irq_flag <= '0'; 285 | else 286 | if set_rx_rdy_flag='1' then 287 | rx_irq_flag <= '1'; 288 | elsif load_stat_reg='1' and data_i(5)='1' then 289 | rx_irq_flag <= '0'; 290 | end if; 291 | if tx_irq='1' then 292 | tx_irq_flag <= '1'; 293 | elsif load_stat_reg='1' and data_i(4)='1' then 294 | tx_irq_flag <= '0'; 295 | end if; 296 | end if; 297 | end if; 298 | end process interrupt_flags; 299 | 300 | 301 | baud_rate_registers: 302 | process(clk) 303 | begin 304 | if clk'event and clk='1' then 305 | if reset = '1' then 306 | bit_period_reg <= to_unsigned(DEFAULT_BIT_PERIOD,14); 307 | else 308 | if wr_i = '1' and ce_i = '1' then 309 | if addr_i = "10" then 310 | bit_period_reg(7 downto 0) <= unsigned(data_i); 311 | elsif addr_i = "11" then 312 | bit_period_reg(13 downto 8) <= unsigned(data_i(5 downto 0)); 313 | end if; 314 | end if; 315 | end if; 316 | end if; 317 | end process baud_rate_registers; 318 | 319 | sampling_period <= bit_period_reg(13 downto 4); 320 | 321 | 322 | -- Receiver -------------------------------------------------------------------- 323 | 324 | baud_counter: 325 | process(clk) 326 | begin 327 | if clk'event and clk='1' then 328 | if reset='1' then 329 | tick_baud_ctr <= (others => '0'); 330 | else 331 | if tick_baud_ctr=sampling_period then 332 | tick_baud_ctr <= (others => '0'); 333 | else 334 | tick_baud_ctr <= tick_baud_ctr + 1; 335 | end if; 336 | end if; 337 | end if; 338 | end process baud_counter; 339 | 340 | tick_ctr_enable<= '1' when tick_baud_ctr=sampling_period else '0'; 341 | 342 | -- Register RxD at the bit sampling rate -- 16 times the baud rate. 343 | rxd_input_register: 344 | process(clk) 345 | begin 346 | if clk'event and clk='1' then 347 | if reset='1' then 348 | rxd_q <= '0'; 349 | else 350 | if tick_ctr_enable='1' then 351 | rxd_q <= rxd; 352 | end if; 353 | end if; 354 | end if; 355 | end process rxd_input_register; 356 | 357 | -- We detect the start bit when... 358 | start_bit_detected <= '1' when 359 | state="0000" and -- ...we're waiting for the start bit... 360 | rxd_q='1' and rxd='0' -- ...and we see RxD going 1-to-0 361 | else '0'; 362 | 363 | -- As soon as we detect the start bit we synchronize the bit sampler to 364 | -- the start bit's falling edge. 365 | reset_tick_ctr <= '1' when start_bit_detected='1' else '0'; 366 | 367 | -- We have seen the end of the stop bit when... 368 | stop_bit_sampled <= '1' when 369 | state="1010" and -- ...we're in the stop bit period... 370 | tick_ctr="1011" -- ...and we get the 11th sample in the bit period 371 | else '0'; 372 | 373 | -- Load the RX buffer with the shift register when... 374 | load_rx_buffer <= '1' when 375 | stop_bit_sampled='1' and -- ...we've just seen the end of the stop bit... 376 | sampled_bit='1' -- ...and its value is correct (1) 377 | else '0'; 378 | 379 | -- Conversely, we detect a stop bit error when... 380 | stop_error <= '1' when 381 | stop_bit_sampled='1' and -- ...we've just seen the end of the stop bit... 382 | sampled_bit='0' -- ...and its value is incorrect (0) 383 | else '0'; 384 | 385 | -- tick_ctr is a counter 16 times faster than the baud rate that is aligned to 386 | -- the falling edge of the start bit, so that when tick_ctr=0 we're close to 387 | -- the start of a bit period. 388 | bit_sample_counter: 389 | process(clk) 390 | begin 391 | if clk'event and clk='1' then 392 | if reset='1' then 393 | tick_ctr <= "0000"; 394 | else 395 | if tick_ctr_enable='1' then 396 | -- Restart counter when it reaches 15 OR when the falling edge 397 | -- of the start bit is detected; this is how we synchronize to the 398 | -- start bit. 399 | if tick_ctr="1111" or reset_tick_ctr='1' then 400 | tick_ctr <= "0000"; 401 | else 402 | tick_ctr <= tick_ctr + 1; 403 | end if; 404 | end if; 405 | end if; 406 | end if; 407 | end process bit_sample_counter; 408 | 409 | -- Main RX state machine: 410 | -- 0 -> waiting for start bit 411 | -- 1 -> sampling start bit 412 | -- 2..9 -> sampling data bit 0 to 7 413 | -- 10 -> sampling stop bit 414 | next_state <= 415 | -- Start sampling the start bit when we detect the falling edge 416 | "0001" when state="0000" and start_bit_detected='1' else 417 | -- Return to idle state if the start bit is not a clean 0 418 | "0000" when state="0001" and tick_ctr="1010" and sampled_bit='1' else 419 | -- Return to idle state at the end of the stop bit period 420 | "0000" when state="1010" and tick_ctr="1111" else 421 | -- Otherwise, proceed to next bit period at the end of each period 422 | state + 1 when tick_ctr="1111" and do_shift='1' else 423 | state; 424 | 425 | rx_state_machine_register: 426 | process(clk) 427 | begin 428 | if clk'event and clk='1' then 429 | if reset='1' then 430 | state <= "0000"; 431 | else 432 | if tick_ctr_enable='1' then 433 | state <= next_state; 434 | end if; 435 | end if; 436 | end if; 437 | end process rx_state_machine_register; 438 | 439 | -- Collect 3 RxD samples from the 3 central sampling periods of the bit period. 440 | rx_sampler: 441 | process(clk) 442 | begin 443 | if clk'event and clk='1' then 444 | if reset='1' then 445 | samples <= "000"; 446 | else 447 | if tick_ctr_enable='1' then 448 | if tick_ctr="0111" then 449 | samples(0) <= rxd; 450 | end if; 451 | if tick_ctr="1000" then 452 | samples(1) <= rxd; 453 | end if; 454 | if tick_ctr="1001" then 455 | samples(2) <= rxd; 456 | end if; 457 | end if; 458 | end if; 459 | end if; 460 | end process rx_sampler; 461 | 462 | -- Decide the value of the RxD bit by majority 463 | with samples select 464 | sampled_bit <= '0' when "000", 465 | '0' when "001", 466 | '0' when "010", 467 | '1' when "011", 468 | '0' when "100", 469 | '1' when "101", 470 | '1' when "110", 471 | '1' when others; 472 | 473 | rx_buffer_register: 474 | process(clk) 475 | begin 476 | if clk'event and clk='1' then 477 | if reset='1' then 478 | rx_buffer <= "00000000"; 479 | set_rx_rdy_flag <= '0'; 480 | else 481 | if tick_ctr_enable='1' and load_rx_buffer='1' and rx_rdy_flag='0' then 482 | rx_buffer <= rx_shift_reg(8 downto 1); 483 | set_rx_rdy_flag <= '1'; 484 | else 485 | set_rx_rdy_flag <= '0'; 486 | end if; 487 | end if; 488 | end if; 489 | end process rx_buffer_register; 490 | 491 | rx_flag: 492 | process(clk) 493 | begin 494 | if clk'event and clk='1' then 495 | if reset='1' then 496 | rx_rdy_flag <= '0'; 497 | else 498 | if set_rx_rdy_flag='1' then 499 | rx_rdy_flag <= '1'; 500 | else 501 | if read_rx = '1' then 502 | rx_rdy_flag <= '0'; 503 | end if; 504 | end if; 505 | end if; 506 | end if; 507 | end process rx_flag; 508 | 509 | -- RX shifter control: shift in any state other than idle state (0) 510 | do_shift <= state(0) or state(1) or state(2) or state(3); 511 | 512 | rx_shift_register: 513 | process(clk) 514 | begin 515 | if clk'event and clk='1' then 516 | if reset='1' then 517 | rx_shift_reg <= "1111111111"; 518 | else 519 | if tick_ctr_enable='1' then 520 | if tick_ctr="1010" and do_shift='1' then 521 | rx_shift_reg(9) <= sampled_bit; 522 | rx_shift_reg(8 downto 0) <= rx_shift_reg(9 downto 1); 523 | end if; 524 | end if; 525 | end if; 526 | end if; 527 | end process rx_shift_register; 528 | 529 | 530 | -- Transmitter ----------------------------------------------------------------- 531 | 532 | 533 | main_tx_process: 534 | process(clk) 535 | begin 536 | if clk'event and clk='1' then 537 | 538 | if reset='1' then 539 | tx_data <= "10111111111"; 540 | tx_busy <= '0'; 541 | tx_irq <= '0'; 542 | tx_ctr_bit <= "0000"; 543 | tx_counter <= (others => '0'); 544 | elsif load_tx_reg='1' and tx_busy='0' then 545 | tx_data <= "1"&data_i&"01"; 546 | tx_busy <= '1'; 547 | else 548 | if tx_busy='1' then 549 | if tx_counter = bit_period_reg then 550 | tx_counter <= (others => '0'); 551 | tx_data(9 downto 0) <= tx_data(10 downto 1); 552 | tx_data(10) <= '1'; 553 | if tx_ctr_bit = "1010" then 554 | tx_busy <= '0'; 555 | tx_irq <= '1'; 556 | tx_ctr_bit <= "0000"; 557 | else 558 | tx_ctr_bit <= tx_ctr_bit + 1; 559 | end if; 560 | else 561 | tx_counter <= tx_counter + 1; 562 | end if; 563 | else 564 | tx_irq <= '0'; 565 | end if; 566 | end if; 567 | end if; 568 | end process main_tx_process; 569 | 570 | txd_o <= tx_data(0); 571 | 572 | end hardwired; 573 | -------------------------------------------------------------------------------- /src/vhdl/rtl/light8080_ucode_pkg.vhdl: -------------------------------------------------------------------------------- 1 | -- light8080_ucode_pkg.vhdl -- Microcode table for light8080 CPU core. 2 | library ieee; 3 | use ieee.std_logic_1164.all; 4 | use ieee.numeric_std.all; 5 | 6 | package light8080_ucode_pkg is 7 | 8 | type t_rom is array (0 to 511) of std_logic_vector(31 downto 0); 9 | constant microcode : t_rom := ( 10 | "00000000000000000000000000000000", -- 000 11 | "00000000000001001000000001000100", -- 001 12 | "00000000000001000000000001000100", -- 002 13 | "10111101101001001000000001001101", -- 003 14 | "10110110101001000000000001001101", -- 004 15 | "00100000000000000000000000000000", -- 005 16 | "00000000000000000000000000000000", -- 006 17 | "11100100000000000000000000000000", -- 007 18 | "00000000101010000000000000000000", -- 008 19 | "00000100000100000000000001010111", -- 009 20 | "00001000000000000000110000011001", -- 00a 21 | "00000100000100000000000001010111", -- 00b 22 | "00000000101010000000000010010111", -- 00c 23 | "00001000000000000000110000011100", -- 00d 24 | "00001000000000000000110000011111", -- 00e 25 | "00000100000100000000000001010111", -- 00f 26 | "00001000000000000000110000011111", -- 010 27 | "00001000000000000000110000011100", -- 011 28 | "00001000000000000000110000011111", -- 012 29 | "00000000000110001000000001010111", -- 013 30 | "00001000000000000000110000011111", -- 014 31 | "00000100000110000000000001010111", -- 015 32 | "00001000000000000000110000101110", -- 016 33 | "00001000000000000000110000100010", -- 017 34 | "00000100000000111000000001010111", -- 018 35 | "00001000000000000000110000101110", -- 019 36 | "00000000101000111000000010010111", -- 01a 37 | "00001000000000000000110000100101", -- 01b 38 | "00001000000000000000110000101110", -- 01c 39 | "10111101101001100000000001001101", -- 01d 40 | "10110110101001101000000001001101", -- 01e 41 | "00000000100000101000000001010111", -- 01f 42 | "00001000000000000000110000100010", -- 020 43 | "00000100000000100000000001010111", -- 021 44 | "00001000000000000000110000101110", -- 022 45 | "00000000101000101000000010010111", -- 023 46 | "10111101101001100000000001001101", -- 024 47 | "10111010101001101000000001001101", -- 025 48 | "00000000101000100000000010010111", -- 026 49 | "00001000000000000000110000100101", -- 027 50 | "00001000000000000000110000101000", -- 028 51 | "00000100000000111000000001010111", -- 029 52 | "00000000101000111000000010010111", -- 02a 53 | "00001000000000000000110000101011", -- 02b 54 | "00000000101000010000000000000000", -- 02c 55 | "00000000000001010000000001010111", -- 02d 56 | "00000000101000011000000000000000", -- 02e 57 | "00000000000001011000000001010111", -- 02f 58 | "00000000101000100000000000000000", -- 030 59 | "00000000000000010000000001010111", -- 031 60 | "00000000101000101000000000000000", -- 032 61 | "00000000000000011000000001010111", -- 033 62 | "00000000101001010000000000000000", -- 034 63 | "00000000000000100000000001010111", -- 035 64 | "00000000101001011000000000000000", -- 036 65 | "00000100000000101000000001010111", -- 037 66 | "00001000000000000000110000011111", -- 038 67 | "00000100011000111000001101001100", -- 039 68 | "00001000000000000000110000011111", -- 03a 69 | "00000100011000111000001101001101", -- 03b 70 | "00001000000000000000110000011111", -- 03c 71 | "00000100011000111000001101001110", -- 03d 72 | "00001000000000000000110000011111", -- 03e 73 | "00000100011000111000001101001111", -- 03f 74 | "00001000000000000000110000011111", -- 040 75 | "00000100011000111100001101000100", -- 041 76 | "00001000000000000000110000011111", -- 042 77 | "00000100011000111100001101000101", -- 043 78 | "00001000000000000000110000011111", -- 044 79 | "00000100011000111100001101000110", -- 045 80 | "00001000000000000000110000011111", -- 046 81 | "00000100011000111000001110001110", -- 047 82 | "00000000101010000000000000000000", -- 048 83 | "00000100011000111000001101001100", -- 049 84 | "00000000101010000000000000000000", -- 04a 85 | "00000100011000111000001101001101", -- 04b 86 | "00000000101010000000000000000000", -- 04c 87 | "00000100011000111000001101001110", -- 04d 88 | "00000000101010000000000000000000", -- 04e 89 | "00000100011000111000001101001111", -- 04f 90 | "00000000101010000000000000000000", -- 050 91 | "00000100011000111100001101000100", -- 051 92 | "00000000101010000000000000000000", -- 052 93 | "00000100011000111100001101000101", -- 053 94 | "00000000101010000000000000000000", -- 054 95 | "00000100011000111100001101000110", -- 055 96 | "00000000101010000000000000000000", -- 056 97 | "00000100011000111000001110001110", -- 057 98 | "00001000000000000000110000011001", -- 058 99 | "00000100011000111000001101001100", -- 059 100 | "00001000000000000000110000011001", -- 05a 101 | "00000100011000111000001101001101", -- 05b 102 | "00001000000000000000110000011001", -- 05c 103 | "00000100011000111000001101001110", -- 05d 104 | "00001000000000000000110000011001", -- 05e 105 | "00000100011000111000001101001111", -- 05f 106 | "00001000000000000000110000011001", -- 060 107 | "00000100011000111100001101000100", -- 061 108 | "00001000000000000000110000011001", -- 062 109 | "00000100011000111100001101000101", -- 063 110 | "00001000000000000000110000011001", -- 064 111 | "00000100011000111100001101000110", -- 065 112 | "00001000000000000000110000011001", -- 066 113 | "00000100011000111000001110001110", -- 067 114 | "10111100101100000000001001001101", -- 068 115 | "00000100000000000000000000000000", -- 069 116 | "00001000000000000000110000011001", -- 06a 117 | "10111100000000000000001010001101", -- 06b 118 | "00001000000000000000110000011100", -- 06c 119 | "10111100011100000000001001001111", -- 06d 120 | "00000100000000000000000000000000", -- 06e 121 | "00001000000000000000110000011001", -- 06f 122 | "11000000000000000000000000000000", -- 070 123 | "10111100011001010000001010001111", -- 071 124 | "00001000000000000000110000011100", -- 072 125 | "10111100101110001000000001001101", -- 073 126 | "10100100101110000000000001001101", -- 074 127 | "10111100011110001000000001001111", -- 075 128 | "10100100011110000000000001001111", -- 076 129 | "00000000011110001000000000000000", -- 077 130 | "00000000101000101000000101001100", -- 078 131 | "00000000011110000000000000000000", -- 079 132 | "00000100101000100000000101001101", -- 07a 133 | "00000000101000111000000010101000", -- 07b 134 | "00000100101000111000001101101000", -- 07c 135 | "00000100101000111000000101000000", -- 07d 136 | "00000100101000111000000101000001", -- 07e 137 | "00000100101000111000000101000010", -- 07f 138 | "00000100101000111000000101000011", -- 080 139 | "00000100101000111000000001000111", -- 081 140 | "00000100000000000000000100101100", -- 082 141 | "00000100000000000000000100101101", -- 083 142 | "00001000000000000000110000101110", -- 084 143 | "00000000101001100000000000000000", -- 085 144 | "00000000000001001000000001010111", -- 086 145 | "00000000101001101000000000000000", -- 087 146 | "00000100000001000000000001010111", -- 088 147 | "00000100000000000000000000000000", -- 089 148 | "00001000000000000000110000101110", -- 08a 149 | "00010000000000000000100000000101", -- 08b 150 | "00001000000000000000110000101110", -- 08c 151 | "11000000101001000000000010010111", -- 08d 152 | "00001000000000000000110000110100", -- 08e 153 | "11000000101001001000000010010111", -- 08f 154 | "00001000000000000000110000110100", -- 090 155 | "00000000101001100000000000000000", -- 091 156 | "00000000000001001000000001010111", -- 092 157 | "00000000101001101000000000000000", -- 093 158 | "00000100000001000000000001010111", -- 094 159 | "00001000000000000000110000101110", -- 095 160 | "00010000000000000000100000001101", -- 096 161 | "00001000000000000000110000111001", -- 097 162 | "00000000000001001000000001010111", -- 098 163 | "00001000000000000000110000111001", -- 099 164 | "00000100000001000000000001010111", -- 09a 165 | "00010000000000000000100000010111", -- 09b 166 | "11000000101001000000000010010111", -- 09c 167 | "00001000000000000000110000110100", -- 09d 168 | "11000000101001001000000010010111", -- 09e 169 | "00001000000000000000110000110100", -- 09f 170 | "11000000000001001000000001011111", -- 0a0 171 | "00000100000001000000000001000100", -- 0a1 172 | "00000000101000101000000000000000", -- 0a2 173 | "00000000000001001000000001010111", -- 0a3 174 | "00000000101000100000000000000000", -- 0a4 175 | "00000100000001000000000001010111", -- 0a5 176 | "11000000101110000000000010010111", -- 0a6 177 | "00001000000000000000110000110100", -- 0a7 178 | "11000000101110001000000010010111", -- 0a8 179 | "00001000000000000000110000110100", -- 0a9 180 | "00000100000000000000000000000000", -- 0aa 181 | "11000000101000111000000010010111", -- 0ab 182 | "00001000000000000000110000110100", -- 0ac 183 | "11000000000000000000000010110000", -- 0ad 184 | "00001000000000000000110000110100", -- 0ae 185 | "00000100000000000000000000000000", -- 0af 186 | "00001000000000000000110000111001", -- 0b0 187 | "00000000000110001000000001010111", -- 0b1 188 | "00001000000000000000110000111001", -- 0b2 189 | "00000100000110000000000001010111", -- 0b3 190 | "00001000000000000000110000111001", -- 0b4 191 | "00000000000000110000001101010111", -- 0b5 192 | "00001000000000000000110000111001", -- 0b6 193 | "00000100000000111000000001010111", -- 0b7 194 | "00001000000000000000110000111001", -- 0b8 195 | "00000000000001100000000001010111", -- 0b9 196 | "00001000000000000000110000111001", -- 0ba 197 | "00000000000001101000000001010111", -- 0bb 198 | "11000000101000100000000010010111", -- 0bc 199 | "00001000000000000000110000110100", -- 0bd 200 | "11000000101000101000000010010111", -- 0be 201 | "00001000000000000000110000110100", -- 0bf 202 | "00000000101001100000000000000000", -- 0c0 203 | "00000000000000101000000001010111", -- 0c1 204 | "00000000101001101000000000000000", -- 0c2 205 | "00000100000000100000000001010111", -- 0c3 206 | "00000000101000101000000000000000", -- 0c4 207 | "00000000000001111000000001010111", -- 0c5 208 | "00000000101000100000000000000000", -- 0c6 209 | "00000100000001110000000001010111", -- 0c7 210 | "01100100000000000000000000000000", -- 0c8 211 | "01000100000000000000000000000000", -- 0c9 212 | "00000000000001101000000001010111", -- 0ca 213 | "00001000000000000000110000011111", -- 0cb 214 | "00000000000001100000000001010111", -- 0cc 215 | "00000000000000000000000000000000", -- 0cd 216 | "00000001101001100000000000000000", -- 0ce 217 | "10010110101001101000000000000000", -- 0cf 218 | "00000100100000111000000001010111", -- 0d0 219 | "00000000000001101000000001010111", -- 0d1 220 | "00001000000000000000110000011111", -- 0d2 221 | "00000000000001100000000001010111", -- 0d3 222 | "00000000101000111000000010010111", -- 0d4 223 | "00000001101001100000000000000000", -- 0d5 224 | "10011010101001101000000000000000", -- 0d6 225 | "00000100000000000000000000000000", -- 0d7 226 | "11100100000000000000000000000000", -- 0d8 227 | "00000001101000101000000000000000", -- 0d9 228 | "00010110101000100000000000000000", -- 0da 229 | "00001100100001010000000001010111", -- 0db 230 | "00000001101000101000000000000000", -- 0dc 231 | "00011010101000100000000000000000", -- 0dd 232 | "00000100000000000000000000000000", -- 0de 233 | "10111101101001001000000001001101", -- 0df 234 | "10110110101001000000000001001101", -- 0e0 235 | "00001100100000000000000010010111", -- 0e1 236 | "00000001101001100000000000000000", -- 0e2 237 | "00010110101001101000000000000000", -- 0e3 238 | "00001100100000000000000000000000", -- 0e4 239 | "00000001101001100000000000000000", -- 0e5 240 | "00011010101001101000000000000000", -- 0e6 241 | "00000100000000000000000000000000", -- 0e7 242 | "00000001101110001000000000000000", -- 0e8 243 | "00010110101110000000000000000000", -- 0e9 244 | "00001100100000000000000000000000", -- 0ea 245 | "00000001101110001000000000000000", -- 0eb 246 | "00011010101110000000000000000000", -- 0ec 247 | "00000100000000000000000000000000", -- 0ed 248 | "10111101101001001000000001001101", -- 0ee 249 | "10110110101001000000000001001101", -- 0ef 250 | "00000000100001100000000001010111", -- 0f0 251 | "10111101101001001000000001001101", -- 0f1 252 | "10110110101001000000000001001101", -- 0f2 253 | "00001100100001101000000001010111", -- 0f3 254 | "10111100011001111000000001001111", -- 0f4 255 | "10100000011001110000000001001111", -- 0f5 256 | "00000001101001111000000000000000", -- 0f6 257 | "00011010101001110000000000000000", -- 0f7 258 | "00001100000000000000000000000000", -- 0f8 259 | "10111101101001111000000001001101", -- 0f9 260 | "10110110101001110000000001001101", -- 0fa 261 | "00001100100000000000000000000000", -- 0fb 262 | "00000100000000000000000000000000", -- 0fc 263 | "00000100000000000000000000000000", -- 0fd 264 | "00000100000000000000000000000000", -- 0fe 265 | "00000100000000000000000000000000", -- 0ff 266 | "00001000000000000000100000001001", -- 100 267 | "00001000000000000000000000010010", -- 101 268 | "00001000000000000000000000101010", -- 102 269 | "00001000000000000000010000110011", -- 103 270 | "00001000000000000000010000101000", -- 104 271 | "00001000000000000000010000101101", -- 105 272 | "00001000000000000000000000001110", -- 106 273 | "00001000000000000000010000111101", -- 107 274 | "00001000000000000000000000000000", -- 108 275 | "00001000000000000000010000110111", -- 109 276 | "00001000000000000000000000101000", -- 10a 277 | "00001000000000000000010000110101", -- 10b 278 | "00001000000000000000010000101000", -- 10c 279 | "00001000000000000000010000101101", -- 10d 280 | "00001000000000000000000000001110", -- 10e 281 | "00001000000000000000010000111110", -- 10f 282 | "00001000000000000000000000000000", -- 110 283 | "00001000000000000000000000010010", -- 111 284 | "00001000000000000000000000101010", -- 112 285 | "00001000000000000000010000110011", -- 113 286 | "00001000000000000000010000101000", -- 114 287 | "00001000000000000000010000101101", -- 115 288 | "00001000000000000000000000001110", -- 116 289 | "00001000000000000000010000111111", -- 117 290 | "00001000000000000000000000000000", -- 118 291 | "00001000000000000000010000110111", -- 119 292 | "00001000000000000000000000101000", -- 11a 293 | "00001000000000000000010000110101", -- 11b 294 | "00001000000000000000010000101000", -- 11c 295 | "00001000000000000000010000101101", -- 11d 296 | "00001000000000000000000000001110", -- 11e 297 | "00001000000000000000100000000000", -- 11f 298 | "00001000000000000000000000000000", -- 120 299 | "00001000000000000000000000010010", -- 121 300 | "00001000000000000000000000100010", -- 122 301 | "00001000000000000000010000110011", -- 123 302 | "00001000000000000000010000101000", -- 124 303 | "00001000000000000000010000101101", -- 125 304 | "00001000000000000000000000001110", -- 126 305 | "00001000000000000000010000111011", -- 127 306 | "00001000000000000000000000000000", -- 128 307 | "00001000000000000000010000110111", -- 129 308 | "00001000000000000000000000011100", -- 12a 309 | "00001000000000000000010000110101", -- 12b 310 | "00001000000000000000010000101000", -- 12c 311 | "00001000000000000000010000101101", -- 12d 312 | "00001000000000000000000000001110", -- 12e 313 | "00001000000000000000100000000001", -- 12f 314 | "00001000000000000000000000000000", -- 130 315 | "00001000000000000000000000010010", -- 131 316 | "00001000000000000000000000011001", -- 132 317 | "00001000000000000000010000110011", -- 133 318 | "00001000000000000000010000101010", -- 134 319 | "00001000000000000000010000101111", -- 135 320 | "00001000000000000000000000010000", -- 136 321 | "00001000000000000000100000000011", -- 137 322 | "00001000000000000000000000000000", -- 138 323 | "00001000000000000000010000110111", -- 139 324 | "00001000000000000000000000010110", -- 13a 325 | "00001000000000000000010000110101", -- 13b 326 | "00001000000000000000010000101000", -- 13c 327 | "00001000000000000000010000101101", -- 13d 328 | "00001000000000000000000000001110", -- 13e 329 | "00001000000000000000100000000010", -- 13f 330 | "00001000000000000000000000001000", -- 140 331 | "00001000000000000000000000001000", -- 141 332 | "00001000000000000000000000001000", -- 142 333 | "00001000000000000000000000001000", -- 143 334 | "00001000000000000000000000001000", -- 144 335 | "00001000000000000000000000001000", -- 145 336 | "00001000000000000000000000001010", -- 146 337 | "00001000000000000000000000001000", -- 147 338 | "00001000000000000000000000001000", -- 148 339 | "00001000000000000000000000001000", -- 149 340 | "00001000000000000000000000001000", -- 14a 341 | "00001000000000000000000000001000", -- 14b 342 | "00001000000000000000000000001000", -- 14c 343 | "00001000000000000000000000001000", -- 14d 344 | "00001000000000000000000000001010", -- 14e 345 | "00001000000000000000000000001000", -- 14f 346 | "00001000000000000000000000001000", -- 150 347 | "00001000000000000000000000001000", -- 151 348 | "00001000000000000000000000001000", -- 152 349 | "00001000000000000000000000001000", -- 153 350 | "00001000000000000000000000001000", -- 154 351 | "00001000000000000000000000001000", -- 155 352 | "00001000000000000000000000001010", -- 156 353 | "00001000000000000000000000001000", -- 157 354 | "00001000000000000000000000001000", -- 158 355 | "00001000000000000000000000001000", -- 159 356 | "00001000000000000000000000001000", -- 15a 357 | "00001000000000000000000000001000", -- 15b 358 | "00001000000000000000000000001000", -- 15c 359 | "00001000000000000000000000001000", -- 15d 360 | "00001000000000000000000000001010", -- 15e 361 | "00001000000000000000000000001000", -- 15f 362 | "00001000000000000000000000001000", -- 160 363 | "00001000000000000000000000001000", -- 161 364 | "00001000000000000000000000001000", -- 162 365 | "00001000000000000000000000001000", -- 163 366 | "00001000000000000000000000001000", -- 164 367 | "00001000000000000000000000001000", -- 165 368 | "00001000000000000000000000001010", -- 166 369 | "00001000000000000000000000001000", -- 167 370 | "00001000000000000000000000001000", -- 168 371 | "00001000000000000000000000001000", -- 169 372 | "00001000000000000000000000001000", -- 16a 373 | "00001000000000000000000000001000", -- 16b 374 | "00001000000000000000000000001000", -- 16c 375 | "00001000000000000000000000001000", -- 16d 376 | "00001000000000000000000000001010", -- 16e 377 | "00001000000000000000000000001000", -- 16f 378 | "00001000000000000000000000001100", -- 170 379 | "00001000000000000000000000001100", -- 171 380 | "00001000000000000000000000001100", -- 172 381 | "00001000000000000000000000001100", -- 173 382 | "00001000000000000000000000001100", -- 174 383 | "00001000000000000000000000001100", -- 175 384 | "00001000000000000000110000011000", -- 176 385 | "00001000000000000000000000001100", -- 177 386 | "00001000000000000000000000001000", -- 178 387 | "00001000000000000000000000001000", -- 179 388 | "00001000000000000000000000001000", -- 17a 389 | "00001000000000000000000000001000", -- 17b 390 | "00001000000000000000000000001000", -- 17c 391 | "00001000000000000000000000001000", -- 17d 392 | "00001000000000000000000000001010", -- 17e 393 | "00001000000000000000000000001000", -- 17f 394 | "00001000000000000000010000001000", -- 180 395 | "00001000000000000000010000001000", -- 181 396 | "00001000000000000000010000001000", -- 182 397 | "00001000000000000000010000001000", -- 183 398 | "00001000000000000000010000001000", -- 184 399 | "00001000000000000000010000001000", -- 185 400 | "00001000000000000000010000011000", -- 186 401 | "00001000000000000000010000001000", -- 187 402 | "00001000000000000000010000001010", -- 188 403 | "00001000000000000000010000001010", -- 189 404 | "00001000000000000000010000001010", -- 18a 405 | "00001000000000000000010000001010", -- 18b 406 | "00001000000000000000010000001010", -- 18c 407 | "00001000000000000000010000001010", -- 18d 408 | "00001000000000000000010000011010", -- 18e 409 | "00001000000000000000010000001010", -- 18f 410 | "00001000000000000000010000001100", -- 190 411 | "00001000000000000000010000001100", -- 191 412 | "00001000000000000000010000001100", -- 192 413 | "00001000000000000000010000001100", -- 193 414 | "00001000000000000000010000001100", -- 194 415 | "00001000000000000000010000001100", -- 195 416 | "00001000000000000000010000011100", -- 196 417 | "00001000000000000000010000001100", -- 197 418 | "00001000000000000000010000001110", -- 198 419 | "00001000000000000000010000001110", -- 199 420 | "00001000000000000000010000001110", -- 19a 421 | "00001000000000000000010000001110", -- 19b 422 | "00001000000000000000010000001110", -- 19c 423 | "00001000000000000000010000001110", -- 19d 424 | "00001000000000000000010000011110", -- 19e 425 | "00001000000000000000010000001110", -- 19f 426 | "00001000000000000000010000010000", -- 1a0 427 | "00001000000000000000010000010000", -- 1a1 428 | "00001000000000000000010000010000", -- 1a2 429 | "00001000000000000000010000010000", -- 1a3 430 | "00001000000000000000010000010000", -- 1a4 431 | "00001000000000000000010000010000", -- 1a5 432 | "00001000000000000000010000100000", -- 1a6 433 | "00001000000000000000010000010000", -- 1a7 434 | "00001000000000000000010000010010", -- 1a8 435 | "00001000000000000000010000010010", -- 1a9 436 | "00001000000000000000010000010010", -- 1aa 437 | "00001000000000000000010000010010", -- 1ab 438 | "00001000000000000000010000010010", -- 1ac 439 | "00001000000000000000010000010010", -- 1ad 440 | "00001000000000000000010000100010", -- 1ae 441 | "00001000000000000000010000010010", -- 1af 442 | "00001000000000000000010000010100", -- 1b0 443 | "00001000000000000000010000010100", -- 1b1 444 | "00001000000000000000010000010100", -- 1b2 445 | "00001000000000000000010000010100", -- 1b3 446 | "00001000000000000000010000010100", -- 1b4 447 | "00001000000000000000010000010100", -- 1b5 448 | "00001000000000000000010000100100", -- 1b6 449 | "00001000000000000000010000010100", -- 1b7 450 | "00001000000000000000010000010110", -- 1b8 451 | "00001000000000000000010000010110", -- 1b9 452 | "00001000000000000000010000010110", -- 1ba 453 | "00001000000000000000010000010110", -- 1bb 454 | "00001000000000000000010000010110", -- 1bc 455 | "00001000000000000000010000010110", -- 1bd 456 | "00001000000000000000010000100110", -- 1be 457 | "00001000000000000000010000010110", -- 1bf 458 | "00001000000000000000100000011011", -- 1c0 459 | "00001000000000000000100000110000", -- 1c1 460 | "00001000000000000000100000001010", -- 1c2 461 | "00001000000000000000100000000100", -- 1c3 462 | "00001000000000000000100000010101", -- 1c4 463 | "00001000000000000000100000100110", -- 1c5 464 | "00001000000000000000000000111000", -- 1c6 465 | "00001000000000000000100000011100", -- 1c7 466 | "00001000000000000000100000011011", -- 1c8 467 | "00001000000000000000100000010111", -- 1c9 468 | "00001000000000000000100000001010", -- 1ca 469 | "00001000000000000000000000000000", -- 1cb 470 | "00001000000000000000100000010101", -- 1cc 471 | "00001000000000000000100000001100", -- 1cd 472 | "00001000000000000000000000111010", -- 1ce 473 | "00001000000000000000100000011100", -- 1cf 474 | "00001000000000000000100000011011", -- 1d0 475 | "00001000000000000000100000110000", -- 1d1 476 | "00001000000000000000100000001010", -- 1d2 477 | "00001000000000000000110000010001", -- 1d3 478 | "00001000000000000000100000010101", -- 1d4 479 | "00001000000000000000100000100110", -- 1d5 480 | "00001000000000000000000000111100", -- 1d6 481 | "00001000000000000000100000011100", -- 1d7 482 | "00001000000000000000100000011011", -- 1d8 483 | "00001000000000000000000000000000", -- 1d9 484 | "00001000000000000000100000001010", -- 1da 485 | "00001000000000000000110000001010", -- 1db 486 | "00001000000000000000100000010101", -- 1dc 487 | "00001000000000000000000000000000", -- 1dd 488 | "00001000000000000000000000111110", -- 1de 489 | "00001000000000000000100000011100", -- 1df 490 | "00001000000000000000100000011011", -- 1e0 491 | "00001000000000000000100000110000", -- 1e1 492 | "00001000000000000000100000001010", -- 1e2 493 | "00001000000000000000100000111000", -- 1e3 494 | "00001000000000000000100000010101", -- 1e4 495 | "00001000000000000000100000100110", -- 1e5 496 | "00001000000000000000010000000000", -- 1e6 497 | "00001000000000000000100000011100", -- 1e7 498 | "00001000000000000000100000011011", -- 1e8 499 | "00001000000000000000100000100010", -- 1e9 500 | "00001000000000000000100000001010", -- 1ea 501 | "00001000000000000000000000101100", -- 1eb 502 | "00001000000000000000100000010101", -- 1ec 503 | "00001000000000000000000000000000", -- 1ed 504 | "00001000000000000000010000000010", -- 1ee 505 | "00001000000000000000100000011100", -- 1ef 506 | "00001000000000000000100000011011", -- 1f0 507 | "00001000000000000000100000110100", -- 1f1 508 | "00001000000000000000100000001010", -- 1f2 509 | "00001000000000000000110000001001", -- 1f3 510 | "00001000000000000000100000010101", -- 1f4 511 | "00001000000000000000100000101011", -- 1f5 512 | "00001000000000000000010000000100", -- 1f6 513 | "00001000000000000000100000011100", -- 1f7 514 | "00001000000000000000100000011011", -- 1f8 515 | "00001000000000000000110000000100", -- 1f9 516 | "00001000000000000000100000001010", -- 1fa 517 | "00001000000000000000110000001000", -- 1fb 518 | "00001000000000000000100000010101", -- 1fc 519 | "00001000000000000000000000000000", -- 1fd 520 | "00001000000000000000010000000110", -- 1fe 521 | "00001000000000000000100000011100" -- 1ff 522 | 523 | ); 524 | end package; 525 | 526 | --------------------------------------------------------------------------------