├── .gitignore ├── COPYING ├── LICENSE ├── Makefile.in ├── README.md ├── aclocal.m4 ├── config.h.in ├── configure ├── configure.ac ├── fesvr ├── context.cc ├── context.h ├── debug_defines.h ├── device.cc ├── device.h ├── dtm.cc ├── dtm.h ├── dummy.cc ├── elf.h ├── elf2hex.cc ├── elfloader.cc ├── elfloader.h ├── encoding.h ├── fesvr.ac ├── fesvr.mk.in ├── fesvr.pc.in ├── htif.cc ├── htif.h ├── htif_hexwriter.cc ├── htif_hexwriter.h ├── htif_pthread.cc ├── htif_pthread.h ├── memif.cc ├── memif.h ├── option_parser.cc ├── option_parser.h ├── rfb.cc ├── rfb.h ├── syscall.cc ├── syscall.h ├── term.cc ├── term.h ├── tsi.cc └── tsi.h ├── riscv-fesvr.pc.in └── scripts ├── config.guess ├── config.sub ├── install.sh ├── mk-install-dirs.sh └── vcs-version.sh /.gitignore: -------------------------------------------------------------------------------- 1 | #========================================================================= 2 | # Git Ignore Files 3 | #========================================================================= 4 | # We explicitly ignore a default build directory and the autoconf 5 | # generated autom4te.cache directory. This makes it easy to do a clean 6 | # build under the source directory and still have it appear clean to git. 7 | 8 | build/ 9 | autom4te.cache/ 10 | 11 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | ========================================================================== 2 | Copyright License 3 | ========================================================================== 4 | 5 | Copyright (c) 2008, Christopher Batten 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are 10 | met: 11 | 12 | * Redistributions of source code must retain the above copyright 13 | notice, this list of conditions, and the following disclaimer. 14 | 15 | * Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions, and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | * Neither the name of the Massachusetts Institute of Technology nor the 20 | names of its contributors may be used to endorse or promote products 21 | derived from this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY Christopher Batten ''AS IS'' AND ANY 24 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Christopher Batten BE LIABLE 27 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 33 | THE POSSIBILITY OF SUCH DAMAGE. 34 | 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, The Regents of the University of California (Regents). 2 | All Rights Reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. Neither the name of the Regents nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, 16 | SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING 17 | OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS 18 | BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 19 | 20 | REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 | PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED 23 | HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE 24 | MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 25 | -------------------------------------------------------------------------------- /Makefile.in: -------------------------------------------------------------------------------- 1 | #========================================================================= 2 | # Toplevel Makefile for the Modular C++ Build System 3 | #========================================================================= 4 | # Please read the documenation in 'mcppbs-doc.txt' for more details on 5 | # how the Modular C++ Build System works. For most projects, a developer 6 | # will not need to make any changes to this makefile. The key targets 7 | # are as follows: 8 | # 9 | # - default : build all libraries and programs 10 | # - check : build and run all unit tests 11 | # - install : install headers, project library, and some programs 12 | # - clean : remove all generated content (except autoconf files) 13 | # - dist : make a source tarball 14 | # - distcheck : make a source tarball, untar it, check it, clean it 15 | # - distclean : remove everything 16 | # 17 | 18 | #------------------------------------------------------------------------- 19 | # Basic setup 20 | #------------------------------------------------------------------------- 21 | 22 | # Remove all default implicit rules since they can cause subtle bugs 23 | # and they just make things run slower 24 | .SUFFIXES: 25 | % : %,v 26 | % : RCS/%,v 27 | % : RCS/% 28 | % : s.% 29 | % : SCCS/s.% 30 | 31 | # Default is to build the prereqs of the all target (defined at bottom) 32 | default : all 33 | .PHONY : default 34 | 35 | project_name := @PACKAGE_TARNAME@ 36 | src_dir := @srcdir@ 37 | scripts_dir := $(src_dir)/scripts 38 | 39 | # If the version information is not in the configure script, then we 40 | # assume that we are in a working directory. We use the vcs-version.sh 41 | # script in the scripts directory to generate an appropriate version 42 | # string. Currently the way things are setup we have to run this script 43 | # everytime we run make so the script needs to be as fast as possible. 44 | 45 | ifeq (@PACKAGE_VERSION@,?) 46 | project_ver:=$(shell $(scripts_dir)/vcs-version.sh $(src_dir)) 47 | else 48 | project_ver:=@PACKAGE_VERSION@ 49 | endif 50 | 51 | # Installation directories 52 | 53 | prefix ?= @prefix@ 54 | enable_stow := @enable_stow@ 55 | 56 | ifeq ($(enable_stow),yes) 57 | stow_pkg_dir := $(prefix)/pkgs 58 | INSTALLDIR ?= $(DESTDIR)$(stow_pkg_dir)/$(project_name)-$(project_ver) 59 | else 60 | INSTALLDIR ?= $(DESTDIR)$(prefix) 61 | endif 62 | 63 | install_hdrs_dir := $(INSTALLDIR)/include/$(project_name) 64 | install_libs_dir := $(INSTALLDIR)/lib 65 | install_exes_dir := $(INSTALLDIR)/bin 66 | 67 | #------------------------------------------------------------------------- 68 | # List of subprojects 69 | #------------------------------------------------------------------------- 70 | 71 | sprojs := @subprojects@ 72 | sprojs_enabled := @subprojects_enabled@ 73 | 74 | sprojs_include := -I. $(addprefix -I$(src_dir)/, $(sprojs_enabled)) 75 | VPATH := $(addprefix $(src_dir)/, $(sprojs_enabled)) 76 | 77 | #------------------------------------------------------------------------- 78 | # Programs and flags 79 | #------------------------------------------------------------------------- 80 | 81 | # C++ compiler 82 | # - CPPFLAGS : flags for the preprocessor (eg. -I,-D) 83 | # - CXXFLAGS : flags for C++ compiler (eg. -Wall,-g,-O3) 84 | 85 | CC := @CC@ 86 | CXX := @CXX@ 87 | CFLAGS += @CFLAGS@ -DPREFIX=\"$(prefix)\" 88 | CPPFLAGS += @CPPFLAGS@ 89 | CXXFLAGS += @CXXFLAGS@ -DPREFIX=\"$(prefix)\" 90 | COMPILE := $(CXX) -fPIC -MMD -MP $(CPPFLAGS) $(CXXFLAGS) \ 91 | $(sprojs_include) 92 | COMPILE_C := $(CC) -fPIC -MMD -MP $(CPPFLAGS) $(CFLAGS) \ 93 | $(sprojs_include) 94 | # Linker 95 | # - LDFLAGS : Flags for the linker (eg. -L) 96 | # - LIBS : Library flags (eg. -l) 97 | 98 | comma := , 99 | LD := $(CXX) 100 | LDFLAGS := @LDFLAGS@ 101 | LIBS := @LIBS@ 102 | LINK := $(LD) -L. $(LDFLAGS) -Wl,-rpath,$(install_libs_dir) $(patsubst -L%,-Wl$(comma)-rpath$(comma)%,$(filter -L%,$(LDFLAGS))) 103 | 104 | # Library creation 105 | 106 | AR := @AR@ 107 | RANLIB := @RANLIB@ 108 | 109 | # Host simulator 110 | 111 | RUN := @RUN@ 112 | RUNFLAGS := @RUNFLAGS@ 113 | 114 | # Installation 115 | 116 | MKINSTALLDIRS := $(scripts_dir)/mk-install-dirs.sh 117 | INSTALL := @INSTALL@ 118 | INSTALL_HDR := $(INSTALL) -m 444 119 | INSTALL_LIB := $(INSTALL) -m 644 120 | INSTALL_EXE := $(INSTALL) -m 555 121 | STOW := @stow@ 122 | 123 | #------------------------------------------------------------------------- 124 | # Include subproject makefile fragments 125 | #------------------------------------------------------------------------- 126 | 127 | sprojs_mk = $(addsuffix .mk, $(sprojs_enabled)) 128 | 129 | -include $(sprojs_mk) 130 | 131 | dist_junk += $(sprojs_mk) 132 | 133 | #------------------------------------------------------------------------- 134 | # Reverse list helper function 135 | #------------------------------------------------------------------------- 136 | # This function is used by the subproject template to reverse the list 137 | # of dependencies. It uses recursion to perform the reversal. 138 | # 139 | # Arguments: 140 | # $(1) : space separated input list 141 | # retval : input list in reverse order 142 | # 143 | 144 | reverse_list = $(call reverse_list_h,$(1),) 145 | define reverse_list_h 146 | $(if $(strip $(1)), \ 147 | $(call reverse_list_h, \ 148 | $(wordlist 2,$(words $(1)),$(1)), \ 149 | $(firstword $(1)) $(2)), \ 150 | $(2)) 151 | endef 152 | 153 | #------------------------------------------------------------------------- 154 | # Template for per subproject rules 155 | #------------------------------------------------------------------------- 156 | # The template is instantiated for each of the subprojects. It relies on 157 | # subprojects defining a certain set of make variables which are all 158 | # prefixed with the subproject name. Since subproject names can have 159 | # dashes in them (and the make variables are assumed to only use 160 | # underscores) the template takes two arguments - one with the regular 161 | # subproject name and one with dashes replaced with underscores. 162 | # 163 | # Arguments: 164 | # $(1) : real subproject name (ie with dashes) 165 | # $(2) : normalized subproject name (ie dashes replaced with underscores) 166 | # 167 | 168 | define subproject_template 169 | 170 | # In some (rare) cases, a subproject might not have any actual object 171 | # files. It might only include header files or program sources. To keep 172 | # things consistent we still want a library for this subproject, so in 173 | # this spectial case we create a dummy source file and thus the build 174 | # system will create a library for this subproject with just the 175 | # corresponding dummy object file. 176 | 177 | ifeq ($$(strip $$($(2)_srcs) $$($(2)_c_srcs)),) 178 | $(2)_srcs += _$(1).cc 179 | $(2)_junk += _$(1).cc 180 | endif 181 | 182 | _$(1).cc : 183 | echo "int _$(2)( int arg ) { return arg; }" > $$@ 184 | 185 | # Build the object files for this subproject 186 | 187 | $(2)_objs := $$(patsubst %.cc, %.o, $$($(2)_srcs)) 188 | $(2)_c_objs := $$(patsubst %.c, %.o, $$($(2)_c_srcs)) 189 | $(2)_deps := $$(patsubst %.o, %.d, $$($(2)_objs)) 190 | $(2)_c_deps := $$(patsubst %.o, %.d, $$($(2)_c_objs)) 191 | $$($(2)_objs) : %.o : %.cc $$($(2)_gen_hdrs) 192 | $(COMPILE) -c $$< 193 | $$($(2)_c_objs) : %.o : %.c $$($(2)_gen_hdrs) 194 | $(COMPILE_C) -c $$< 195 | 196 | $(2)_junk += $$($(2)_objs) $$($(2)_c_objs) $$($(2)_deps) $$($(2)_c_deps) $$($(2)_gen_hdrs) 197 | 198 | # Reverse the dependency list so that a given subproject only depends on 199 | # subprojects listed to its right. This is the correct order for linking 200 | # the list of subproject libraries. 201 | 202 | $(2)_reverse_deps := $$(call reverse_list,$$($(2)_subproject_deps)) 203 | 204 | # Build a library for this subproject 205 | 206 | $(2)_lib_libs := $$($(2)_reverse_deps) 207 | $(2)_lib_libnames := $$(patsubst %, lib%.so, $$($(2)_lib_libs)) 208 | $(2)_lib_libarg := $$(patsubst %, -l%, $$($(2)_lib_libs)) 209 | 210 | lib$(1).so : $$($(2)_objs) $$($(2)_c_objs) $$($(2)_lib_libnames) 211 | $(LINK) -shared -o $$@ $(if $(filter Darwin,$(shell uname -s)),-install_name $(install_libs_dir)/$$@) $$^ $$($(2)_lib_libarg) $(LIBS) 212 | 213 | $(2)_junk += lib$(1).so 214 | 215 | # Build unit tests 216 | 217 | $(2)_test_objs := $$(patsubst %.cc, %.o, $$($(2)_test_srcs)) 218 | $(2)_test_deps := $$(patsubst %.o, %.d, $$($(2)_test_objs)) 219 | $(2)_test_exes := $$(patsubst %.t.cc, %-utst, $$($(2)_test_srcs)) 220 | $(2)_test_outs := $$(patsubst %, %.out, $$($(2)_test_exes)) 221 | $(2)_test_libs := $(1) $$($(2)_reverse_deps) utst 222 | $(2)_test_libnames := $$(patsubst %, lib%.so, $$($(2)_test_libs)) 223 | $(2)_test_libarg := $$(patsubst %, -l%, $$($(2)_test_libs)) 224 | 225 | $$($(2)_test_objs) : %.o : %.cc 226 | $(COMPILE) -c $$< 227 | 228 | $$($(2)_test_exes) : %-utst : %.t.o $$($(2)_test_libnames) 229 | $(LINK) -o $$@ $$< $$($(2)_test_libarg) $(LIBS) 230 | 231 | $(2)_deps += $$($(2)_test_deps) 232 | $(2)_junk += \ 233 | $$($(2)_test_objs) $$($(2)_test_deps) \ 234 | $$($(2)_test_exes) *.junk-dat 235 | 236 | # Run unit tests 237 | 238 | $$($(2)_test_outs) : %.out : % 239 | $(RUN) $(RUNFLAGS) ./$$< default | tee $$@ 240 | 241 | $(2)_junk += $$($(2)_test_outs) 242 | 243 | # Build programs 244 | 245 | $(2)_prog_objs := $$(patsubst %.cc, %.o, $$($(2)_prog_srcs)) 246 | $(2)_prog_deps := $$(patsubst %.o, %.d, $$($(2)_prog_objs)) 247 | $(2)_prog_exes := $$(patsubst %.cc, %, $$($(2)_prog_srcs)) 248 | $(2)_prog_libs := $(1) $$($(2)_reverse_deps) 249 | $(2)_prog_libnames := $$(patsubst %, lib%.so, $$($(2)_prog_libs)) 250 | $(2)_prog_libarg := $$(patsubst %, -l%, $$($(2)_prog_libs)) 251 | 252 | $$($(2)_prog_objs) : %.o : %.cc 253 | $(COMPILE) -c $$< 254 | 255 | $$($(2)_prog_exes) : % : %.o $$($(2)_prog_libnames) 256 | $(LINK) -o $$@ $$< $$($(2)_prog_libarg) $(LIBS) 257 | 258 | $(2)_deps += $$($(2)_prog_deps) 259 | $(2)_junk += $$($(2)_prog_objs) $$($(2)_prog_deps) $$($(2)_prog_exes) 260 | 261 | # Build programs which will be installed 262 | 263 | $(2)_install_prog_objs := $$(patsubst %.cc, %.o, $$($(2)_install_prog_srcs)) 264 | $(2)_install_prog_deps := $$(patsubst %.o, %.d, $$($(2)_install_prog_objs)) 265 | $(2)_install_prog_exes := $$(patsubst %.cc, %, $$($(2)_install_prog_srcs)) 266 | 267 | $$($(2)_install_prog_objs) : %.o : %.cc $$($(2)_gen_hdrs) 268 | $(COMPILE) -c $$< 269 | 270 | $$($(2)_install_prog_exes) : % : %.o $$($(2)_prog_libnames) 271 | $(LINK) -o $$@ $$< $$($(2)_prog_libarg) $(LIBS) 272 | 273 | $(2)_deps += $$($(2)_install_prog_deps) 274 | $(2)_junk += \ 275 | $$($(2)_install_prog_objs) $$($(2)_install_prog_deps) \ 276 | $$($(2)_install_prog_exes) 277 | 278 | # Subproject specific targets 279 | 280 | all-$(1) : lib$(1).so $$($(2)_install_prog_exes) 281 | 282 | check-$(1) : $$($(2)_test_outs) 283 | echo; grep -h -e'Unit Tests' -e'FAILED' -e'Segementation' $$^; echo 284 | 285 | clean-$(1) : 286 | rm -rf $$($(2)_junk) 287 | 288 | .PHONY : all-$(1) check-$(1) clean-$(1) 289 | 290 | # Update running variables 291 | 292 | libs += lib$(1).so 293 | objs += $$($(2)_objs) 294 | srcs += $$(addprefix $(src_dir)/$(1)/, $$($(2)_srcs)) 295 | hdrs += $$(addprefix $(src_dir)/$(1)/, $$($(2)_hdrs)) $$($(2)_gen_hdrs) 296 | junk += $$($(2)_junk) 297 | deps += $$($(2)_deps) 298 | 299 | test_outs += $$($(2)_test_outs) 300 | 301 | install_hdrs += $$(addprefix $(src_dir)/$(1)/, $$($(2)_hdrs)) $$($(2)_gen_hdrs) 302 | install_libs += lib$(1).so 303 | install_exes += $$($(2)_install_prog_exes) 304 | install_pcs += riscv-$(1).pc 305 | 306 | endef 307 | 308 | # Iterate over the subprojects and call the template for each one 309 | 310 | $(foreach sproj,$(sprojs_enabled), \ 311 | $(eval $(call subproject_template,$(sproj),$(subst -,_,$(sproj))))) 312 | 313 | #------------------------------------------------------------------------- 314 | # Autodependency files 315 | #------------------------------------------------------------------------- 316 | 317 | -include $(deps) 318 | 319 | deps : $(deps) 320 | .PHONY : deps 321 | 322 | #------------------------------------------------------------------------- 323 | # Check 324 | #------------------------------------------------------------------------- 325 | 326 | check : $(test_outs) 327 | echo; grep -h -e'Unit Tests' -e'FAILED' -e'Segementation' $^; echo 328 | 329 | .PHONY : check 330 | 331 | #------------------------------------------------------------------------- 332 | # Installation 333 | #------------------------------------------------------------------------- 334 | 335 | install-hdrs : $(install_hdrs) 336 | $(MKINSTALLDIRS) $(install_hdrs_dir) 337 | for file in $^; \ 338 | do \ 339 | $(INSTALL_HDR) $$file $(install_hdrs_dir); \ 340 | done 341 | 342 | install-libs : $(install_libs) 343 | $(MKINSTALLDIRS) $(install_libs_dir) 344 | for file in $^; \ 345 | do \ 346 | $(INSTALL_LIB) $$file $(install_libs_dir); \ 347 | done 348 | 349 | install-exes : $(install_exes) 350 | $(MKINSTALLDIRS) $(install_exes_dir) 351 | for file in $^; \ 352 | do \ 353 | $(INSTALL_EXE) $$file $(install_exes_dir); \ 354 | done 355 | 356 | install-pc : $(install_pcs) 357 | $(MKINSTALLDIRS) $(install_libs_dir)/pkgconfig/ 358 | for file in $^; \ 359 | do \ 360 | $(INSTALL_HDR) $$file $(install_libs_dir)/pkgconfig/; \ 361 | done 362 | 363 | install : install-hdrs install-libs install-exes install-pc 364 | ifeq ($(enable_stow),yes) 365 | $(MKINSTALLDIRS) $(stow_pkg_dir) 366 | cd $(stow_pkg_dir) && \ 367 | $(STOW) --delete $(project_name)-* && \ 368 | $(STOW) $(project_name)-$(project_ver) 369 | endif 370 | 371 | .PHONY : install install-hdrs install-libs install-exes 372 | 373 | #------------------------------------------------------------------------- 374 | # Regenerate configure information 375 | #------------------------------------------------------------------------- 376 | 377 | config.status : $(src_dir)/configure 378 | ./config.status --recheck 379 | 380 | sprojs_mk_in = \ 381 | $(join $(addprefix $(src_dir)/, $(sprojs_enabled)), \ 382 | $(patsubst %, /%.mk.in, $(sprojs_enabled))) 383 | 384 | Makefile : $(src_dir)/Makefile.in $(sprojs_mk_in) config.status 385 | ./config.status 386 | 387 | dist_junk += config.status config.h Makefile config.log 388 | 389 | #------------------------------------------------------------------------- 390 | # Distribution 391 | #------------------------------------------------------------------------- 392 | # The distribution tarball is named project-ver.tar.gz and it includes 393 | # both enabled and disabled subprojects. 394 | 395 | dist_files = \ 396 | $(sprojs) \ 397 | README \ 398 | style-guide.txt \ 399 | mcppbs-uguide.txt \ 400 | scripts \ 401 | configure.ac \ 402 | aclocal.m4 \ 403 | configure \ 404 | config.h.in \ 405 | Makefile.in \ 406 | 407 | dist_dir := $(project_name)-$(project_ver) 408 | dist_tgz := $(project_name)-$(project_ver).tar.gz 409 | 410 | # Notice that when we make the distribution we rewrite the configure.ac 411 | # script with the current version and we rerun autoconf in the new 412 | # source directory so that the distribution will have the proper version 413 | # information. We also rewrite the "Version : " line in the README. 414 | 415 | dist : 416 | rm -rf $(dist_dir) 417 | mkdir $(dist_dir) 418 | tar -C $(src_dir) -cf - $(dist_files) | tar -C $(dist_dir) -xpf - 419 | sed -i.bak 's/^\(# Version :\).*/\1 $(project_ver)/' $(dist_dir)/README 420 | sed -i.bak 's/\( proj_version,\).*/\1 [$(project_ver)])/' $(dist_dir)/configure.ac 421 | cd $(dist_dir) && \ 422 | autoconf && autoheader && \ 423 | rm -rf autom4te.cache configure.ac.bak README.bak 424 | tar -czvf $(dist_tgz) $(dist_dir) 425 | rm -rf $(dist_dir) 426 | 427 | # You can use the distcheck target to try untarring the distribution and 428 | # then running configure, make, make check, and make distclean. A 429 | # "directory is not empty" error means distclean is not removing 430 | # everything. 431 | 432 | distcheck : dist 433 | rm -rf $(dist_dir) 434 | tar -xzvf $(dist_tgz) 435 | mkdir -p $(dist_dir)/build 436 | cd $(dist_dir)/build; ../configure; make; make check; make distclean 437 | rm -rf $(dist_dir) 438 | 439 | junk += $(project_name)-*.tar.gz 440 | 441 | .PHONY : dist distcheck 442 | 443 | #------------------------------------------------------------------------- 444 | # Default 445 | #------------------------------------------------------------------------- 446 | 447 | all : $(install_hdrs) $(install_libs) $(install_exes) 448 | .PHONY : all 449 | 450 | #------------------------------------------------------------------------- 451 | # Makefile debugging 452 | #------------------------------------------------------------------------- 453 | # This handy rule will display the contents of any make variable by 454 | # using the target debug-. So for example, make debug-junk will 455 | # display the contents of the junk variable. 456 | 457 | debug-% : 458 | @echo $* = $($*) 459 | 460 | #------------------------------------------------------------------------- 461 | # Clean up junk 462 | #------------------------------------------------------------------------- 463 | 464 | clean : 465 | rm -rf *~ \#* $(junk) 466 | 467 | distclean : 468 | rm -rf *~ \#* $(junk) $(dist_junk) 469 | 470 | .PHONY : clean distclean 471 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | RISC-V Frontend Server 2 | ========================= 3 | 4 | About 5 | --------- 6 | 7 | This repository is deprecated; it has been absorbed into the Spike 8 | repository (https://github.com/riscv/riscv-isa-sim). 9 | -------------------------------------------------------------------------------- /aclocal.m4: -------------------------------------------------------------------------------- 1 | #========================================================================= 2 | # Local Autoconf Macros 3 | #========================================================================= 4 | # This file contains the macros for the Modular C++ Build System and 5 | # additional autoconf macros which developers can use in their 6 | # configure.ac scripts. Please read the documentation in 7 | # 'mcppbs-doc.txt' for more details on how the Modular C++ Build System 8 | # works. The documenation for each macro should include information 9 | # about the author, date, and copyright. 10 | 11 | #------------------------------------------------------------------------- 12 | # MCPPBS_PROG_INSTALL 13 | #------------------------------------------------------------------------- 14 | # This macro will add an --enable-stow command line option to the 15 | # configure script. When enabled, this macro will first check to see if 16 | # the stow program is available and if so it will set the $stow shell 17 | # variable to the binary name and the $enable_stow shell variable to 18 | # "yes". These variables can be used in a makefile to conditionally use 19 | # stow for installation. 20 | # 21 | # This macro uses two environment variables to help setup default stow 22 | # locations. The $STOW_PREFIX is used for stowing native built packages. 23 | # The packages are staged in $STOW_PREFIX/pkgs and then symlinks are 24 | # created from within $STOW_PREFIX into the pkgs subdirectory. If you 25 | # only do native builds then this is all you need to set. If you don't 26 | # set $STOW_PREFIX then the default is just the normal default prefix 27 | # which is almost always /usr/local. 28 | # 29 | # For non-native builds we probably want to install the packages in a 30 | # different location which includes the host architecture name as part 31 | # of the prefix. For these kind of builds, we can specify the $STOW_ROOT 32 | # environment variable and the effective prefix will be 33 | # $STOW_ROOT/${host_alias} where ${host_alias} is specified on the 34 | # configure command line with "--host". 35 | # 36 | # Here is an example setup: 37 | # 38 | # STOW_ROOT="$HOME/install" 39 | # STOW_ARCH="i386-macosx10.4" 40 | # STOW_PREFIX="${STOW_ROOT}/${STOW_ARCH}" 41 | # 42 | 43 | AC_DEFUN([MCPPBS_PROG_INSTALL], 44 | [ 45 | 46 | # Configure command line option 47 | 48 | AC_ARG_ENABLE(stow, 49 | AS_HELP_STRING(--enable-stow,[Enable stow-based install]), 50 | [enable_stow="yes"],[enable_stow="no"]) 51 | 52 | AC_SUBST([enable_stow]) 53 | 54 | # Environment variables 55 | 56 | AC_ARG_VAR([STOW_ROOT], [Root for non-native stow-based installs]) 57 | AC_ARG_VAR([STOW_PREFIX], [Prefix for stow-based installs]) 58 | 59 | # Check for install script 60 | 61 | AC_PROG_INSTALL 62 | 63 | # Deterimine if native build and set prefix appropriately 64 | 65 | AS_IF([ test ${enable_stow} = "yes" ], 66 | [ 67 | AC_CHECK_PROGS([stow],[stow],[no]) 68 | AS_IF([ test ${stow} = "no" ], 69 | [ 70 | AC_MSG_ERROR([Cannot use --enable-stow since stow is not available]) 71 | ]) 72 | 73 | # Check if native or non-native build 74 | 75 | AS_IF([ test "${build}" = "${host}" ], 76 | [ 77 | 78 | # build == host so this is a native build. Make sure --prefix not 79 | # set and $STOW_PREFIX is set, then set prefix=$STOW_PREFIX. 80 | 81 | AS_IF([ test "${prefix}" = "NONE" && test -n "${STOW_PREFIX}" ], 82 | [ 83 | prefix="${STOW_PREFIX}" 84 | AC_MSG_NOTICE([Using \$STOW_PREFIX from environment]) 85 | AC_MSG_NOTICE([prefix=${prefix}]) 86 | ]) 87 | 88 | ],[ 89 | 90 | # build != host so this is a non-native build. Make sure --prefix 91 | # not set and $STOW_ROOT is set, then set 92 | # prefix=$STOW_ROOT/${host_alias}. 93 | 94 | AS_IF([ test "${prefix}" = "NONE" && test -n "${STOW_ROOT}" ], 95 | [ 96 | prefix="${STOW_ROOT}/${host_alias}" 97 | AC_MSG_NOTICE([Using \$STOW_ROOT from environment]) 98 | AC_MSG_NOTICE([prefix=${prefix}]) 99 | ]) 100 | 101 | ]) 102 | 103 | ]) 104 | 105 | ]) 106 | 107 | #------------------------------------------------------------------------- 108 | # MCPPBS_PROG_RUN 109 | # ------------------------------------------------------------------------- 110 | # If we are doing a non-native build then we look for an isa simulator 111 | # to use for running tests. We set the RUN substitution variable to be 112 | # empty for native builds or to the name of the isa simulator for 113 | # non-native builds. Thus a makefile can run compiled programs 114 | # regardless if we are doing a native or non-native build like this: 115 | # 116 | # $(RUN) $(RUNFLAGS) ./test-program 117 | # 118 | 119 | AC_DEFUN([MCPPBS_PROG_RUN], 120 | [ 121 | AS_IF([ test "${build}" != "${host}" ], 122 | [ 123 | AC_CHECK_TOOLS([RUN],[isa-run run],[no]) 124 | AS_IF([ test ${RUN} = "no" ], 125 | [ 126 | AC_MSG_ERROR([Cannot find simulator for target ${target_alias}]) 127 | ]) 128 | ],[ 129 | RUN="" 130 | ]) 131 | AC_SUBST([RUN]) 132 | AC_SUBST([RUNFLAGS]) 133 | ]) 134 | 135 | #------------------------------------------------------------------------- 136 | # MCPPBS_SUBPROJECTS([ sproj1, sproj2, ... ]) 137 | #------------------------------------------------------------------------- 138 | # The developer should call this macro with a list of the subprojects 139 | # which make up this project. One should order the list such that any 140 | # given subproject only depends on subprojects listed before it. The 141 | # subproject names can also include an * suffix which indicates that 142 | # this is an optional subproject. Optional subprojects are only included 143 | # as part of the project build if enabled on the configure command line 144 | # with a --enable- flag. The user can also specify that all 145 | # optional subprojects should be included in the build with the 146 | # --enable-optional-subprojects flag. 147 | # 148 | # Subproject names can also include a ** suffix which indicates that it 149 | # is an optional subproject, but there is a group with the same name. 150 | # Thus the --enable- command line option will enable not just the 151 | # subproject sproj but all of the subprojects which are in the group. 152 | # There is no error checking to make sure that if you use the ** suffix 153 | # you actually define a group so be careful. 154 | # 155 | # Both required and optional subprojects should have a 'subproject.ac' 156 | # file. The script's filename should be the abbreivated subproject name 157 | # (assuming the subproject name is sproj then we would use 'sproj.ac') 158 | # The MCPPBS_SUBPROJECTS macro includes the 'subproject.ac' files for 159 | # enabled subprojects. Whitespace and newlines are allowed within the 160 | # list. 161 | # 162 | # Author : Christopher Batten 163 | # Date : September 10, 2008 164 | 165 | AC_DEFUN([MCPPBS_SUBPROJECTS], 166 | [ 167 | 168 | # Add command line argument to enable all optional subprojects 169 | 170 | AC_ARG_ENABLE(optional-subprojects, 171 | AS_HELP_STRING([--enable-optional-subprojects], 172 | [Enable all optional subprojects])) 173 | 174 | # Loop through the subprojects given in the macro argument 175 | 176 | m4_foreach([MCPPBS_SPROJ],[$1], 177 | [ 178 | 179 | # Determine if this is a required or an optional subproject 180 | 181 | m4_define([MCPPBS_IS_REQ], 182 | m4_bmatch(MCPPBS_SPROJ,[\*+],[false],[true])) 183 | 184 | # Determine if there is a group with the same name 185 | 186 | m4_define([MCPPBS_IS_GROUP], 187 | m4_bmatch(MCPPBS_SPROJ,[\*\*],[true],[false])) 188 | 189 | # Create variations of the subproject name suitable for use as a CPP 190 | # enabled define, a shell enabled variable, and a shell function 191 | 192 | m4_define([MCPPBS_SPROJ_NORM], 193 | m4_normalize(m4_bpatsubsts(MCPPBS_SPROJ,[*],[]))) 194 | 195 | m4_define([MCPPBS_SPROJ_DEFINE], 196 | m4_toupper(m4_bpatsubst(MCPPBS_SPROJ_NORM[]_ENABLED,[-],[_]))) 197 | 198 | m4_define([MCPPBS_SPROJ_FUNC], 199 | m4_bpatsubst(_mpbp_[]MCPPBS_SPROJ_NORM[]_configure,[-],[_])) 200 | 201 | m4_define([MCPPBS_SPROJ_UNDERSCORES], 202 | m4_bpatsubsts(MCPPBS_SPROJ,[-],[_])) 203 | 204 | m4_define([MCPPBS_SPROJ_SHVAR], 205 | m4_bpatsubst(enable_[]MCPPBS_SPROJ_NORM[]_sproj,[-],[_])) 206 | 207 | # Add subproject to our running list 208 | 209 | subprojects="$subprojects MCPPBS_SPROJ_NORM" 210 | 211 | # Process the subproject appropriately. If enabled add it to the 212 | # $enabled_subprojects running shell variable, set a 213 | # SUBPROJECT_ENABLED C define, and include the appropriate 214 | # 'subproject.ac'. 215 | 216 | m4_if(MCPPBS_IS_REQ,[true], 217 | [ 218 | AC_MSG_NOTICE([configuring default subproject : MCPPBS_SPROJ_NORM]) 219 | AC_CONFIG_FILES(MCPPBS_SPROJ_NORM[].mk:MCPPBS_SPROJ_NORM[]/MCPPBS_SPROJ_NORM[].mk.in) 220 | MCPPBS_SPROJ_SHVAR="yes" 221 | subprojects_enabled="$subprojects_enabled MCPPBS_SPROJ_NORM" 222 | AC_DEFINE(MCPPBS_SPROJ_DEFINE,, 223 | [Define if subproject MCPPBS_SPROJ_NORM is enabled]) 224 | m4_include(MCPPBS_SPROJ_NORM[]/MCPPBS_SPROJ_NORM[].ac) 225 | ],[ 226 | 227 | # For optional subprojects we capture the 'subproject.ac' as a 228 | # shell function so that in the MCPPBS_GROUP macro we can just 229 | # call this shell function instead of reading in 'subproject.ac' 230 | # again. 231 | 232 | MCPPBS_SPROJ_FUNC () 233 | { 234 | AC_MSG_NOTICE([configuring optional subproject : MCPPBS_SPROJ_NORM]) 235 | AC_CONFIG_FILES(MCPPBS_SPROJ_NORM[].mk:MCPPBS_SPROJ_NORM[]/MCPPBS_SPROJ_NORM[].mk.in) 236 | MCPPBS_SPROJ_SHVAR="yes" 237 | subprojects_enabled="$subprojects_enabled MCPPBS_SPROJ_NORM" 238 | AC_DEFINE(MCPPBS_SPROJ_DEFINE,, 239 | [Define if subproject MCPPBS_SPROJ_NORM is enabled]) 240 | m4_include(MCPPBS_SPROJ_NORM[]/MCPPBS_SPROJ_NORM[].ac) 241 | }; 242 | 243 | # Optional subprojects add --enable-subproject command line 244 | # options, _if_ the subproject name is not also a group name. 245 | 246 | m4_if(MCPPBS_IS_GROUP,[false], 247 | [ 248 | AC_ARG_ENABLE(MCPPBS_SPROJ_NORM, 249 | AS_HELP_STRING(--enable-MCPPBS_SPROJ_NORM, 250 | [Subproject MCPPBS_SPROJ_NORM]), 251 | [MCPPBS_SPROJ_SHVAR="yes"],[MCPPBS_SPROJ_SHVAR="no"]) 252 | 253 | AS_IF([test "$MCPPBS_SPROJ_SHVAR" = "yes"], 254 | [ 255 | eval "MCPPBS_SPROJ_FUNC" 256 | ],[ 257 | AC_MSG_NOTICE([processing optional subproject : MCPPBS_SPROJ_NORM]) 258 | ]) 259 | 260 | ],[ 261 | 262 | # If the subproject name is also a group name then we need to 263 | # make sure that we set the shell variable for that subproject to 264 | # no so that the group code knows we haven't run it yet. 265 | 266 | AC_MSG_NOTICE([processing optional subproject : MCPPBS_SPROJ_NORM]) 267 | MCPPBS_SPROJ_SHVAR="no" 268 | 269 | ]) 270 | 271 | # Always execute the subproject configure code if we are enabling 272 | # all subprojects. 273 | 274 | AS_IF([ test "$enable_optional_subprojects" = "yes" \ 275 | && test "$MCPPBS_SPROJ_SHVAR" = "no" ], 276 | [ 277 | eval "MCPPBS_SPROJ_FUNC" 278 | ]) 279 | 280 | ]) 281 | 282 | ]) 283 | 284 | # Output make variables 285 | 286 | AC_SUBST([subprojects]) 287 | AC_SUBST([subprojects_enabled]) 288 | 289 | ]) 290 | 291 | #------------------------------------------------------------------------- 292 | # MCPPBS_GROUP( [group-name], [ sproj1, sproj2, ... ] ) 293 | #------------------------------------------------------------------------- 294 | # This macro creates a subproject group with the given group-name. When 295 | # a user specifies --enable- the listed subprojects will be 296 | # enabled. Groups can have the same name as a subproject and in that 297 | # case whenever a user specifies --enable- the subprojects 298 | # listed in the corresponding group will also be enabled. Groups are 299 | # useful for specifying related subprojects which are usually enabled 300 | # together, as well as for specifying that a specific optional 301 | # subproject has dependencies on other optional subprojects. 302 | # 303 | # Author : Christopher Batten 304 | # Date : September 10, 2008 305 | 306 | AC_DEFUN([MCPPBS_GROUP], 307 | [ 308 | 309 | m4_define([MCPPBS_GROUP_NORM], 310 | m4_normalize([$1])) 311 | 312 | m4_define([MCPPBS_GROUP_SHVAR], 313 | m4_bpatsubst(enable_[]MCPPBS_GROUP_NORM[]_group,[-],[_])) 314 | 315 | AC_ARG_ENABLE(MCPPBS_GROUP_NORM, 316 | AS_HELP_STRING(--enable-MCPPBS_GROUP_NORM, 317 | [Group MCPPBS_GROUP_NORM: $2]), 318 | [MCPPBS_GROUP_SHVAR="yes"],[MCPPBS_GROUP_SHVAR="no"]) 319 | 320 | AS_IF([test "$MCPPBS_GROUP_SHVAR" = "yes" ], 321 | [ 322 | AC_MSG_NOTICE([configuring optional group : MCPPBS_GROUP_NORM]) 323 | ]) 324 | 325 | m4_foreach([MCPPBS_SPROJ],[$2], 326 | [ 327 | 328 | m4_define([MCPPBS_SPROJ_NORM], 329 | m4_normalize(MCPPBS_SPROJ)) 330 | 331 | m4_define([MCPPBS_SPROJ_SHVAR], 332 | m4_bpatsubst(enable_[]MCPPBS_SPROJ_NORM[]_sproj,[-],[_])) 333 | 334 | m4_define([MCPPBS_SPROJ_FUNC], 335 | m4_bpatsubst(_mpbp_[]MCPPBS_SPROJ_NORM[]_configure,[-],[_])) 336 | 337 | AS_IF([ test "$MCPPBS_GROUP_SHVAR" = "yes" \ 338 | && test "$MCPPBS_SPROJ_SHVAR" = "no" ], 339 | [ 340 | eval "MCPPBS_SPROJ_FUNC" 341 | ]) 342 | 343 | ]) 344 | 345 | ]) 346 | -------------------------------------------------------------------------------- /config.h.in: -------------------------------------------------------------------------------- 1 | /* config.h.in. Generated from configure.ac by autoheader. */ 2 | 3 | /* Define if subproject MCPPBS_SPROJ_NORM is enabled */ 4 | #undef FESVR_ENABLED 5 | 6 | /* Define to 1 if you have the `pthread' library (-lpthread). */ 7 | #undef HAVE_LIBPTHREAD 8 | 9 | /* Define to the address where bug reports for this package should be sent. */ 10 | #undef PACKAGE_BUGREPORT 11 | 12 | /* Define to the full name of this package. */ 13 | #undef PACKAGE_NAME 14 | 15 | /* Define to the full name and version of this package. */ 16 | #undef PACKAGE_STRING 17 | 18 | /* Define to the one symbol short name of this package. */ 19 | #undef PACKAGE_TARNAME 20 | 21 | /* Define to the home page for this package. */ 22 | #undef PACKAGE_URL 23 | 24 | /* Define to the version of this package. */ 25 | #undef PACKAGE_VERSION 26 | 27 | /* Define to 1 if you have the ANSI C header files. */ 28 | #undef STDC_HEADERS 29 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | #========================================================================= 2 | # Toplevel configure.ac for the Modular C++ Build System 3 | #========================================================================= 4 | # Please read the documenation in 'mcppbs-doc.txt' for more details on 5 | # how the Modular C++ Build System works. For most new projects, a 6 | # developer will only need to make the following changes: 7 | # 8 | # - change the project metadata listed right below 9 | # - update the list of subprojects via the 'MCPPBS_SUBPROJECTS' macro 10 | # - possibly add subproject groups if needed to ease configuration 11 | # - add more configure checks for platform specific configuration 12 | # 13 | 14 | #------------------------------------------------------------------------- 15 | # Project metadata 16 | #------------------------------------------------------------------------- 17 | 18 | m4_define( proj_name, [RISC-V Frontend Server]) 19 | m4_define( proj_maintainer, [Andrew Waterman]) 20 | m4_define( proj_abbreviation, [fesvr]) 21 | 22 | #------------------------------------------------------------------------- 23 | # Project version information 24 | #------------------------------------------------------------------------- 25 | # Version information is meant to be managed through a version control 26 | # system's tags and revision numbers. In a working copy the version will 27 | # not be defined here (you should just use the version control system's 28 | # mechanisms). When we make a distribution then we can set the version 29 | # here as formed by the scripts/vcs-version.sh script so that the 30 | # distribution knows what version it came from. If you are not using 31 | # version control then it is fine to set this directly. 32 | 33 | m4_define( proj_version, [?]) 34 | 35 | #------------------------------------------------------------------------- 36 | # Setup 37 | #------------------------------------------------------------------------- 38 | 39 | AC_INIT(proj_name,proj_version,proj_maintainer,proj_abbreviation) 40 | AC_CONFIG_SRCDIR([fesvr/htif.h]) 41 | AC_CONFIG_AUX_DIR([scripts]) 42 | AC_CANONICAL_BUILD 43 | AC_CANONICAL_HOST 44 | 45 | #------------------------------------------------------------------------- 46 | # Checks for programs 47 | #------------------------------------------------------------------------- 48 | 49 | AC_PROG_CC 50 | AC_PROG_CXX 51 | AC_CHECK_TOOL([AR],[ar]) 52 | AC_CHECK_TOOL([RANLIB],[ranlib]) 53 | 54 | #------------------------------------------------------------------------- 55 | # MCPPBS specific program check 56 | #------------------------------------------------------------------------- 57 | # This macro check to see if we can do a stow-based install. 58 | 59 | MCPPBS_PROG_INSTALL 60 | 61 | #------------------------------------------------------------------------- 62 | # Checks for header files 63 | #------------------------------------------------------------------------- 64 | 65 | AC_HEADER_STDC 66 | 67 | #------------------------------------------------------------------------- 68 | # Default compiler flags 69 | #------------------------------------------------------------------------- 70 | 71 | AC_SUBST([CFLAGS], ["-Wall -O2"]) 72 | AC_SUBST([CXXFLAGS],["-Wall -O2 -std=c++11"]) 73 | 74 | if test "x$target_alias" != x; then 75 | CFLAGS="$CFLAGS -DTARGET_ARCH=\\\"$target_alias\\\"" 76 | CXXFLAGS="$CXXFLAGS -DTARGET_ARCH=\\\"$target_alias\\\"" 77 | fi 78 | 79 | #------------------------------------------------------------------------- 80 | # MCPPBS subproject list 81 | #------------------------------------------------------------------------- 82 | # Order list so that subprojects only depend on those listed earlier. 83 | # The '*' suffix indicates an optional subproject. The '**' suffix 84 | # indicates an optional subproject which is also the name of a group. 85 | 86 | MCPPBS_SUBPROJECTS([fesvr]) 87 | 88 | #------------------------------------------------------------------------- 89 | # MCPPBS subproject groups 90 | #------------------------------------------------------------------------- 91 | # If a group has the same name as a subproject then you must add the 92 | # '**' suffix in the subproject list above. The list of subprojects in a 93 | # group should be ordered so that subprojets only depend on those listed 94 | # earlier. Here is an example: 95 | # 96 | # MCPPBS_GROUP( [group-name], [sproja,sprojb,...] ) 97 | # 98 | 99 | #------------------------------------------------------------------------- 100 | # Output 101 | #------------------------------------------------------------------------- 102 | 103 | AC_CONFIG_HEADERS([config.h]) 104 | AC_CONFIG_FILES([Makefile]) 105 | AC_CONFIG_FILES([riscv-fesvr.pc]) 106 | AC_OUTPUT 107 | -------------------------------------------------------------------------------- /fesvr/context.cc: -------------------------------------------------------------------------------- 1 | #include "context.h" 2 | #include 3 | #include 4 | #include 5 | 6 | static __thread context_t* cur; 7 | 8 | context_t::context_t() 9 | : creator(NULL), func(NULL), arg(NULL), 10 | #ifndef USE_UCONTEXT 11 | mutex(PTHREAD_MUTEX_INITIALIZER), 12 | cond(PTHREAD_COND_INITIALIZER), flag(0) 13 | #else 14 | context(new ucontext_t) 15 | #endif 16 | { 17 | } 18 | 19 | #ifdef USE_UCONTEXT 20 | #ifndef GLIBC_64BIT_PTR_BUG 21 | void context_t::wrapper(context_t* ctx) 22 | { 23 | #else 24 | void context_t::wrapper(unsigned int hi, unsigned int lo) 25 | { 26 | context_t* ctx = reinterpret_cast(static_cast(lo) | (static_cast(hi) << 32)); 27 | #endif 28 | ctx->creator->switch_to(); 29 | ctx->func(ctx->arg); 30 | } 31 | #else 32 | void* context_t::wrapper(void* a) 33 | { 34 | context_t* ctx = static_cast(a); 35 | cur = ctx; 36 | ctx->creator->switch_to(); 37 | 38 | ctx->func(ctx->arg); 39 | return NULL; 40 | } 41 | #endif 42 | 43 | void context_t::init(void (*f)(void*), void* a) 44 | { 45 | func = f; 46 | arg = a; 47 | creator = current(); 48 | 49 | #ifdef USE_UCONTEXT 50 | getcontext(context.get()); 51 | context->uc_link = creator->context.get(); 52 | context->uc_stack.ss_size = 64*1024; 53 | context->uc_stack.ss_sp = new void*[context->uc_stack.ss_size/sizeof(void*)]; 54 | #ifndef GLIBC_64BIT_PTR_BUG 55 | makecontext(context.get(), (void(*)(void))&context_t::wrapper, 1, this); 56 | #else 57 | unsigned int hi(reinterpret_cast(this) >> 32); 58 | unsigned int lo(reinterpret_cast(this)); 59 | makecontext(context.get(), (void(*)(void))&context_t::wrapper, 2, hi, lo); 60 | #endif 61 | switch_to(); 62 | #else 63 | assert(flag == 0); 64 | 65 | pthread_mutex_lock(&creator->mutex); 66 | creator->flag = 0; 67 | if (pthread_create(&thread, NULL, &context_t::wrapper, this) != 0) 68 | abort(); 69 | pthread_detach(thread); 70 | while (!creator->flag) 71 | pthread_cond_wait(&creator->cond, &creator->mutex); 72 | pthread_mutex_unlock(&creator->mutex); 73 | #endif 74 | } 75 | 76 | context_t::~context_t() 77 | { 78 | assert(this != cur); 79 | } 80 | 81 | void context_t::switch_to() 82 | { 83 | assert(this != cur); 84 | #ifdef USE_UCONTEXT 85 | context_t* prev = cur; 86 | cur = this; 87 | if (swapcontext(prev->context.get(), context.get()) != 0) 88 | abort(); 89 | #else 90 | cur->flag = 0; 91 | this->flag = 1; 92 | pthread_mutex_lock(&this->mutex); 93 | pthread_cond_signal(&this->cond); 94 | pthread_mutex_unlock(&this->mutex); 95 | pthread_mutex_lock(&cur->mutex); 96 | while (!cur->flag) 97 | pthread_cond_wait(&cur->cond, &cur->mutex); 98 | pthread_mutex_unlock(&cur->mutex); 99 | #endif 100 | } 101 | 102 | context_t* context_t::current() 103 | { 104 | if (cur == NULL) 105 | { 106 | cur = new context_t; 107 | #ifdef USE_UCONTEXT 108 | getcontext(cur->context.get()); 109 | #else 110 | cur->thread = pthread_self(); 111 | cur->flag = 1; 112 | #endif 113 | } 114 | return cur; 115 | } 116 | -------------------------------------------------------------------------------- /fesvr/context.h: -------------------------------------------------------------------------------- 1 | #ifndef _HTIF_CONTEXT_H 2 | #define _HTIF_CONTEXT_H 3 | 4 | // A replacement for ucontext.h, which is sadly deprecated. 5 | 6 | #include 7 | 8 | #if defined(__GLIBC__) 9 | # undef USE_UCONTEXT 10 | # define USE_UCONTEXT 11 | # include 12 | # include 13 | #include 14 | 15 | #if (ULONG_MAX > UINT_MAX) // 64-bit systems only 16 | #if (100*GLIB_MAJOR_VERSION+GLIB_MINOR_VERSION < 208) 17 | #define GLIBC_64BIT_PTR_BUG 18 | static_assert (sizeof(unsigned int) == 4, "uint size doesn't match expected 32bit"); 19 | static_assert (sizeof(unsigned long) == 8, "ulong size doesn't match expected 64bit"); 20 | static_assert (sizeof(void*) == 8, "ptr size doesn't match expected 64bit"); 21 | #endif 22 | #endif /* ULONG_MAX > UINT_MAX */ 23 | 24 | #endif 25 | 26 | class context_t 27 | { 28 | public: 29 | context_t(); 30 | ~context_t(); 31 | void init(void (*func)(void*), void* arg); 32 | void switch_to(); 33 | static context_t* current(); 34 | private: 35 | context_t* creator; 36 | void (*func)(void*); 37 | void* arg; 38 | #ifdef USE_UCONTEXT 39 | std::unique_ptr context; 40 | #ifndef GLIBC_64BIT_PTR_BUG 41 | static void wrapper(context_t*); 42 | #else 43 | static void wrapper(unsigned int, unsigned int); 44 | #endif 45 | #else 46 | pthread_t thread; 47 | pthread_mutex_t mutex; 48 | pthread_cond_t cond; 49 | volatile int flag; 50 | static void* wrapper(void*); 51 | #endif 52 | }; 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /fesvr/device.cc: -------------------------------------------------------------------------------- 1 | #include "device.h" 2 | #include "term.h" 3 | #include "memif.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | using namespace std::placeholders; 13 | 14 | device_t::device_t() 15 | : command_handlers(command_t::MAX_COMMANDS), 16 | command_names(command_t::MAX_COMMANDS) 17 | { 18 | for (size_t cmd = 0; cmd < command_t::MAX_COMMANDS; cmd++) 19 | register_command(cmd, std::bind(&device_t::handle_null_command, this, _1), ""); 20 | register_command(command_t::MAX_COMMANDS-1, std::bind(&device_t::handle_identify, this, _1), "identity"); 21 | } 22 | 23 | void device_t::register_command(size_t cmd, command_func_t handler, const char* name) 24 | { 25 | assert(cmd < command_t::MAX_COMMANDS); 26 | assert(strlen(name) < IDENTITY_SIZE); 27 | command_handlers[cmd] = handler; 28 | command_names[cmd] = name; 29 | } 30 | 31 | void device_t::handle_command(command_t cmd) 32 | { 33 | command_handlers[cmd.cmd()](cmd); 34 | } 35 | 36 | void device_t::handle_null_command(command_t cmd) 37 | { 38 | } 39 | 40 | void device_t::handle_identify(command_t cmd) 41 | { 42 | size_t what = cmd.payload() % command_t::MAX_COMMANDS; 43 | uint64_t addr = cmd.payload() / command_t::MAX_COMMANDS; 44 | assert(addr % IDENTITY_SIZE == 0); 45 | 46 | char id[IDENTITY_SIZE] = {0}; 47 | if (what == command_t::MAX_COMMANDS-1) 48 | { 49 | assert(strlen(identity()) < IDENTITY_SIZE); 50 | strcpy(id, identity()); 51 | } 52 | else 53 | strcpy(id, command_names[what].c_str()); 54 | 55 | cmd.memif().write(addr, IDENTITY_SIZE, id); 56 | cmd.respond(1); 57 | } 58 | 59 | bcd_t::bcd_t() 60 | { 61 | register_command(0, std::bind(&bcd_t::handle_read, this, _1), "read"); 62 | register_command(1, std::bind(&bcd_t::handle_write, this, _1), "write"); 63 | } 64 | 65 | void bcd_t::handle_read(command_t cmd) 66 | { 67 | pending_reads.push(cmd); 68 | } 69 | 70 | void bcd_t::handle_write(command_t cmd) 71 | { 72 | canonical_terminal_t::write(cmd.payload()); 73 | } 74 | 75 | void bcd_t::tick() 76 | { 77 | int ch; 78 | if (!pending_reads.empty() && (ch = canonical_terminal_t::read()) != -1) 79 | { 80 | pending_reads.front().respond(0x100 | ch); 81 | pending_reads.pop(); 82 | } 83 | } 84 | 85 | disk_t::disk_t(const char* fn) 86 | { 87 | fd = ::open(fn, O_RDWR); 88 | if (fd < 0) 89 | throw std::runtime_error("could not open " + std::string(fn)); 90 | 91 | register_command(0, std::bind(&disk_t::handle_read, this, _1), "read"); 92 | register_command(1, std::bind(&disk_t::handle_write, this, _1), "write"); 93 | 94 | struct stat st; 95 | if (fstat(fd, &st) < 0) 96 | throw std::runtime_error("could not stat " + std::string(fn)); 97 | 98 | size = st.st_size; 99 | id = "disk size=" + std::to_string(size); 100 | } 101 | 102 | disk_t::~disk_t() 103 | { 104 | close(fd); 105 | } 106 | 107 | void disk_t::handle_read(command_t cmd) 108 | { 109 | request_t req; 110 | cmd.memif().read(cmd.payload(), sizeof(req), &req); 111 | 112 | std::vector buf(req.size); 113 | if ((size_t)::pread(fd, &buf[0], buf.size(), req.offset) != req.size) 114 | throw std::runtime_error("could not read " + id + " @ " + std::to_string(req.offset)); 115 | 116 | cmd.memif().write(req.addr, buf.size(), &buf[0]); 117 | cmd.respond(req.tag); 118 | } 119 | 120 | void disk_t::handle_write(command_t cmd) 121 | { 122 | request_t req; 123 | cmd.memif().read(cmd.payload(), sizeof(req), &req); 124 | 125 | std::vector buf(req.size); 126 | cmd.memif().read(req.addr, buf.size(), &buf[0]); 127 | 128 | if ((size_t)::pwrite(fd, &buf[0], buf.size(), req.offset) != req.size) 129 | throw std::runtime_error("could not write " + id + " @ " + std::to_string(req.offset)); 130 | 131 | cmd.respond(req.tag); 132 | } 133 | 134 | device_list_t::device_list_t() 135 | : devices(command_t::MAX_COMMANDS, &null_device), num_devices(0) 136 | { 137 | } 138 | 139 | void device_list_t::register_device(device_t* dev) 140 | { 141 | num_devices++; 142 | assert(num_devices < command_t::MAX_DEVICES); 143 | devices[num_devices-1] = dev; 144 | } 145 | 146 | void device_list_t::handle_command(command_t cmd) 147 | { 148 | devices[cmd.device()]->handle_command(cmd); 149 | } 150 | 151 | void device_list_t::tick() 152 | { 153 | for (size_t i = 0; i < num_devices; i++) 154 | devices[i]->tick(); 155 | } 156 | -------------------------------------------------------------------------------- /fesvr/device.h: -------------------------------------------------------------------------------- 1 | #ifndef _DEVICE_H 2 | #define _DEVICE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | class memif_t; 11 | 12 | class command_t 13 | { 14 | public: 15 | typedef std::function callback_t; 16 | command_t(memif_t& memif, uint64_t tohost, callback_t cb) 17 | : _memif(memif), tohost(tohost), cb(cb) {} 18 | 19 | memif_t& memif() { return _memif; } 20 | uint8_t device() { return tohost >> 56; } 21 | uint8_t cmd() { return tohost >> 48; } 22 | uint64_t payload() { return tohost << 16 >> 16; } 23 | void respond(uint64_t resp) { cb((tohost >> 48 << 48) | (resp << 16 >> 16)); } 24 | 25 | static const size_t MAX_COMMANDS = 256; 26 | static const size_t MAX_DEVICES = 256; 27 | 28 | private: 29 | memif_t& _memif; 30 | uint64_t tohost; 31 | callback_t cb; 32 | }; 33 | 34 | class device_t 35 | { 36 | public: 37 | device_t(); 38 | virtual ~device_t() {} 39 | virtual const char* identity() = 0; 40 | virtual void tick() {} 41 | 42 | void handle_command(command_t cmd); 43 | 44 | protected: 45 | typedef std::function command_func_t; 46 | void register_command(size_t, command_func_t, const char*); 47 | 48 | private: 49 | device_t& operator = (const device_t&); // disallow 50 | device_t(const device_t&); // disallow 51 | 52 | static const size_t IDENTITY_SIZE = 64; 53 | void handle_null_command(command_t cmd); 54 | void handle_identify(command_t cmd); 55 | 56 | std::vector command_handlers; 57 | std::vector command_names; 58 | }; 59 | 60 | class bcd_t : public device_t 61 | { 62 | public: 63 | bcd_t(); 64 | const char* identity() { return "bcd"; } 65 | void tick(); 66 | 67 | private: 68 | void handle_read(command_t cmd); 69 | void handle_write(command_t cmd); 70 | 71 | std::queue pending_reads; 72 | }; 73 | 74 | class disk_t : public device_t 75 | { 76 | public: 77 | disk_t(const char* fn); 78 | ~disk_t(); 79 | const char* identity() { return id.c_str(); } 80 | 81 | private: 82 | struct request_t 83 | { 84 | uint64_t addr; 85 | uint64_t offset; 86 | uint64_t size; 87 | uint64_t tag; 88 | }; 89 | 90 | void handle_read(command_t cmd); 91 | void handle_write(command_t cmd); 92 | 93 | std::string id; 94 | size_t size; 95 | int fd; 96 | }; 97 | 98 | class null_device_t : public device_t 99 | { 100 | public: 101 | const char* identity() { return ""; } 102 | }; 103 | 104 | class device_list_t 105 | { 106 | public: 107 | device_list_t(); 108 | void register_device(device_t* dev); 109 | void handle_command(command_t cmd); 110 | void tick(); 111 | 112 | private: 113 | std::vector devices; 114 | null_device_t null_device; 115 | size_t num_devices; 116 | }; 117 | 118 | #endif 119 | -------------------------------------------------------------------------------- /fesvr/dtm.cc: -------------------------------------------------------------------------------- 1 | #include "dtm.h" 2 | #include "debug_defines.h" 3 | #include "encoding.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define RV_X(x, s, n) \ 11 | (((x) >> (s)) & ((1 << (n)) - 1)) 12 | #define ENCODE_ITYPE_IMM(x) \ 13 | (RV_X(x, 0, 12) << 20) 14 | #define ENCODE_STYPE_IMM(x) \ 15 | ((RV_X(x, 0, 5) << 7) | (RV_X(x, 5, 7) << 25)) 16 | #define ENCODE_SBTYPE_IMM(x) \ 17 | ((RV_X(x, 1, 4) << 8) | (RV_X(x, 5, 6) << 25) | (RV_X(x, 11, 1) << 7) | (RV_X(x, 12, 1) << 31)) 18 | #define ENCODE_UTYPE_IMM(x) \ 19 | (RV_X(x, 12, 20) << 12) 20 | #define ENCODE_UJTYPE_IMM(x) \ 21 | ((RV_X(x, 1, 10) << 21) | (RV_X(x, 11, 1) << 20) | (RV_X(x, 12, 8) << 12) | (RV_X(x, 20, 1) << 31)) 22 | 23 | #define LOAD(xlen, dst, base, imm) \ 24 | (((xlen) == 64 ? 0x00003003 : 0x00002003) \ 25 | | ((dst) << 7) | ((base) << 15) | (uint32_t)ENCODE_ITYPE_IMM(imm)) 26 | #define STORE(xlen, src, base, imm) \ 27 | (((xlen) == 64 ? 0x00003023 : 0x00002023) \ 28 | | ((src) << 20) | ((base) << 15) | (uint32_t)ENCODE_STYPE_IMM(imm)) 29 | #define JUMP(there, here) (0x6f | (uint32_t)ENCODE_UJTYPE_IMM((there) - (here))) 30 | #define BNE(r1, r2, there, here) (0x1063 | ((r1) << 15) | ((r2) << 20) | (uint32_t)ENCODE_SBTYPE_IMM((there) - (here))) 31 | #define ADDI(dst, src, imm) (0x13 | ((dst) << 7) | ((src) << 15) | (uint32_t)ENCODE_ITYPE_IMM(imm)) 32 | #define SRL(dst, src, sh) (0x5033 | ((dst) << 7) | ((src) << 15) | ((sh) << 20)) 33 | #define FENCE_I 0x100f 34 | #define EBREAK 0x00100073 35 | #define X0 0 36 | #define S0 8 37 | #define S1 9 38 | 39 | #define AC_AR_REGNO(x) ((0x1000 | x) << AC_ACCESS_REGISTER_REGNO_OFFSET) 40 | #define AC_AR_SIZE(x) (((x == 128)? 4 : (x == 64 ? 3 : 2)) << AC_ACCESS_REGISTER_SIZE_OFFSET) 41 | 42 | #define WRITE 1 43 | #define SET 2 44 | #define CLEAR 3 45 | #define CSRRx(type, dst, csr, src) (0x73 | ((type) << 12) | ((dst) << 7) | ((src) << 15) | (uint32_t)((csr) << 20)) 46 | 47 | #define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1))) 48 | #define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask))) 49 | 50 | #define RUN_AC_OR_DIE(a, b, c, d, e) { \ 51 | uint32_t cmderr = run_abstract_command(a, b, c, d, e); \ 52 | if (cmderr) { \ 53 | die(cmderr); \ 54 | } \ 55 | } 56 | 57 | uint32_t dtm_t::do_command(dtm_t::req r) 58 | { 59 | req_buf = r; 60 | target->switch_to(); 61 | assert(resp_buf.resp == 0); 62 | return resp_buf.data; 63 | } 64 | 65 | uint32_t dtm_t::read(uint32_t addr) 66 | { 67 | return do_command((req){addr, 1, 0}); 68 | } 69 | 70 | uint32_t dtm_t::write(uint32_t addr, uint32_t data) 71 | { 72 | return do_command((req){addr, 2, data}); 73 | } 74 | 75 | void dtm_t::nop() 76 | { 77 | do_command((req){0, 0, 0}); 78 | } 79 | 80 | void dtm_t::select_hart(int hartsel) { 81 | int dmcontrol = read(DMI_DMCONTROL); 82 | write (DMI_DMCONTROL, set_field(dmcontrol, DMI_DMCONTROL_HARTSEL, hartsel)); 83 | current_hart = hartsel; 84 | } 85 | 86 | int dtm_t::enumerate_harts() { 87 | int max_hart = (1 << DMI_DMCONTROL_HARTSEL_LENGTH) - 1; 88 | write(DMI_DMCONTROL, set_field(read(DMI_DMCONTROL), DMI_DMCONTROL_HARTSEL, max_hart)); 89 | read(DMI_DMSTATUS); 90 | max_hart = get_field(read(DMI_DMCONTROL), DMI_DMCONTROL_HARTSEL); 91 | 92 | int hartsel; 93 | for (hartsel = 0; hartsel <= max_hart; hartsel++) { 94 | select_hart(hartsel); 95 | int dmstatus = read(DMI_DMSTATUS); 96 | if (get_field(dmstatus, DMI_DMSTATUS_ANYNONEXISTENT)) 97 | break; 98 | } 99 | return hartsel; 100 | } 101 | 102 | void dtm_t::halt(int hartsel) 103 | { 104 | if (running) { 105 | write(DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE); 106 | // Read dmstatus to avoid back-to-back writes to dmcontrol. 107 | read(DMI_DMSTATUS); 108 | } 109 | 110 | int dmcontrol = DMI_DMCONTROL_HALTREQ | DMI_DMCONTROL_DMACTIVE; 111 | dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_HARTSEL, hartsel); 112 | write(DMI_DMCONTROL, dmcontrol); 113 | int dmstatus; 114 | do { 115 | dmstatus = read(DMI_DMSTATUS); 116 | } while(get_field(dmstatus, DMI_DMSTATUS_ALLHALTED) == 0); 117 | dmcontrol &= ~DMI_DMCONTROL_HALTREQ; 118 | write(DMI_DMCONTROL, dmcontrol); 119 | // Read dmstatus to avoid back-to-back writes to dmcontrol. 120 | read(DMI_DMSTATUS); 121 | current_hart = hartsel; 122 | } 123 | 124 | void dtm_t::resume(int hartsel) 125 | { 126 | int dmcontrol = DMI_DMCONTROL_RESUMEREQ | DMI_DMCONTROL_DMACTIVE; 127 | dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_HARTSEL, hartsel); 128 | write(DMI_DMCONTROL, dmcontrol); 129 | int dmstatus; 130 | do { 131 | dmstatus = read(DMI_DMSTATUS); 132 | } while (get_field(dmstatus, DMI_DMSTATUS_ALLRESUMEACK) == 0); 133 | dmcontrol &= ~DMI_DMCONTROL_RESUMEREQ; 134 | write(DMI_DMCONTROL, dmcontrol); 135 | // Read dmstatus to avoid back-to-back writes to dmcontrol. 136 | read(DMI_DMSTATUS); 137 | current_hart = hartsel; 138 | 139 | if (running) { 140 | write(DMI_DMCONTROL, 0); 141 | // Read dmstatus to avoid back-to-back writes to dmcontrol. 142 | read(DMI_DMSTATUS); 143 | } 144 | } 145 | 146 | uint64_t dtm_t::save_reg(unsigned regno) 147 | { 148 | uint32_t data[xlen/(8*4)]; 149 | uint32_t command = AC_ACCESS_REGISTER_TRANSFER | AC_AR_SIZE(xlen) | AC_AR_REGNO(regno); 150 | RUN_AC_OR_DIE(command, 0, 0, data, xlen / (8*4)); 151 | 152 | uint64_t result = data[0]; 153 | if (xlen > 32) { 154 | result |= ((uint64_t)data[1]) << 32; 155 | } 156 | return result; 157 | } 158 | 159 | void dtm_t::restore_reg(unsigned regno, uint64_t val) 160 | { 161 | uint32_t data[xlen/(8*4)]; 162 | data[0] = (uint32_t) val; 163 | if (xlen > 32) { 164 | data[1] = (uint32_t) (val >> 32); 165 | } 166 | 167 | uint32_t command = AC_ACCESS_REGISTER_TRANSFER | 168 | AC_ACCESS_REGISTER_WRITE | 169 | AC_AR_SIZE(xlen) | 170 | AC_AR_REGNO(regno); 171 | 172 | RUN_AC_OR_DIE(command, 0, 0, data, xlen / (8*4)); 173 | 174 | } 175 | 176 | uint32_t dtm_t::run_abstract_command(uint32_t command, 177 | const uint32_t program[], size_t program_n, 178 | uint32_t data[], size_t data_n) 179 | { 180 | assert(program_n <= ram_words); 181 | assert(data_n <= data_words); 182 | 183 | for (size_t i = 0; i < program_n; i++) { 184 | write(DMI_PROGBUF0 + i, program[i]); 185 | } 186 | 187 | if (get_field(command, AC_ACCESS_REGISTER_WRITE) && 188 | get_field(command, AC_ACCESS_REGISTER_TRANSFER)) { 189 | for (size_t i = 0; i < data_n; i++) { 190 | write(DMI_DATA0 + i, data[i]); 191 | } 192 | } 193 | 194 | write(DMI_COMMAND, command); 195 | 196 | // Wait for not busy and then check for error. 197 | uint32_t abstractcs; 198 | do { 199 | abstractcs = read(DMI_ABSTRACTCS); 200 | } while (abstractcs & DMI_ABSTRACTCS_BUSY); 201 | 202 | if ((get_field(command, AC_ACCESS_REGISTER_WRITE) == 0) && 203 | get_field(command, AC_ACCESS_REGISTER_TRANSFER)) { 204 | for (size_t i = 0; i < data_n; i++){ 205 | data[i] = read(DMI_DATA0 + i); 206 | } 207 | } 208 | 209 | return get_field(abstractcs, DMI_ABSTRACTCS_CMDERR); 210 | 211 | } 212 | 213 | size_t dtm_t::chunk_align() 214 | { 215 | return xlen / 8; 216 | } 217 | 218 | void dtm_t::read_chunk(uint64_t taddr, size_t len, void* dst) 219 | { 220 | uint32_t prog[ram_words]; 221 | uint32_t data[data_words]; 222 | 223 | uint8_t * curr = (uint8_t*) dst; 224 | 225 | halt(current_hart); 226 | 227 | uint64_t s0 = save_reg(S0); 228 | uint64_t s1 = save_reg(S1); 229 | 230 | prog[0] = LOAD(xlen, S1, S0, 0); 231 | prog[1] = ADDI(S0, S0, xlen/8); 232 | prog[2] = EBREAK; 233 | 234 | data[0] = (uint32_t) taddr; 235 | if (xlen > 32) { 236 | data[1] = (uint32_t) (taddr >> 32); 237 | } 238 | 239 | // Write s0 with the address, then execute program buffer. 240 | // This will get S1 with the data and increment s0. 241 | uint32_t command = AC_ACCESS_REGISTER_TRANSFER | 242 | AC_ACCESS_REGISTER_WRITE | 243 | AC_ACCESS_REGISTER_POSTEXEC | 244 | AC_AR_SIZE(xlen) | 245 | AC_AR_REGNO(S0); 246 | 247 | RUN_AC_OR_DIE(command, prog, 3, data, xlen/(4*8)); 248 | 249 | // TODO: could use autoexec here. 250 | for (size_t i = 0; i < (len * 8 / xlen); i++){ 251 | command = AC_ACCESS_REGISTER_TRANSFER | 252 | AC_AR_SIZE(xlen) | 253 | AC_AR_REGNO(S1); 254 | if ((i + 1) < (len * 8 / xlen)) { 255 | command |= AC_ACCESS_REGISTER_POSTEXEC; 256 | } 257 | 258 | RUN_AC_OR_DIE(command, 0, 0, data, xlen/(4*8)); 259 | 260 | memcpy(curr, data, xlen/8); 261 | curr += xlen/8; 262 | } 263 | 264 | restore_reg(S0, s0); 265 | restore_reg(S1, s1); 266 | 267 | resume(current_hart); 268 | 269 | } 270 | 271 | void dtm_t::write_chunk(uint64_t taddr, size_t len, const void* src) 272 | { 273 | uint32_t prog[ram_words]; 274 | uint32_t data[data_words]; 275 | 276 | const uint8_t * curr = (const uint8_t*) src; 277 | 278 | halt(current_hart); 279 | 280 | uint64_t s0 = save_reg(S0); 281 | uint64_t s1 = save_reg(S1); 282 | 283 | prog[0] = STORE(xlen, S1, S0, 0); 284 | prog[1] = ADDI(S0, S0, xlen/8); 285 | prog[2] = EBREAK; 286 | 287 | data[0] = (uint32_t) taddr; 288 | if (xlen > 32) { 289 | data[1] = (uint32_t) (taddr >> 32); 290 | } 291 | 292 | // Write the program (not used yet). 293 | // Write s0 with the address. 294 | uint32_t command = AC_ACCESS_REGISTER_TRANSFER | 295 | AC_ACCESS_REGISTER_WRITE | 296 | AC_AR_SIZE(xlen) | 297 | AC_AR_REGNO(S0); 298 | 299 | RUN_AC_OR_DIE(command, prog, 3, data, xlen/(4*8)); 300 | 301 | // Use Autoexec for more than one word of transfer. 302 | // Write S1 with data, then execution stores S1 to 303 | // 0(S0) and increments S0. 304 | // Each time we write XLEN bits. 305 | memcpy(data, curr, xlen/8); 306 | curr += xlen/8; 307 | 308 | command = AC_ACCESS_REGISTER_TRANSFER | 309 | AC_ACCESS_REGISTER_POSTEXEC | 310 | AC_ACCESS_REGISTER_WRITE | 311 | AC_AR_SIZE(xlen) | 312 | AC_AR_REGNO(S1); 313 | 314 | RUN_AC_OR_DIE(command, 0, 0, data, xlen/(4*8)); 315 | 316 | uint32_t abstractcs; 317 | for (size_t i = 1; i < (len * 8 / xlen); i++){ 318 | if (i == 1) { 319 | write(DMI_ABSTRACTAUTO, 1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); 320 | } 321 | memcpy(data, curr, xlen/8); 322 | curr += xlen/8; 323 | if (xlen == 64) { 324 | write(DMI_DATA0 + 1, data[1]); 325 | } 326 | write(DMI_DATA0, data[0]); //Triggers a command w/ autoexec. 327 | 328 | do { 329 | abstractcs = read(DMI_ABSTRACTCS); 330 | } while (abstractcs & DMI_ABSTRACTCS_BUSY); 331 | if ( get_field(abstractcs, DMI_ABSTRACTCS_CMDERR)) { 332 | die(get_field(abstractcs, DMI_ABSTRACTCS_CMDERR)); 333 | } 334 | } 335 | if ((len * 8 / xlen) > 1) { 336 | write(DMI_ABSTRACTAUTO, 0); 337 | } 338 | 339 | restore_reg(S0, s0); 340 | restore_reg(S1, s1); 341 | resume(current_hart); 342 | } 343 | 344 | void dtm_t::die(uint32_t cmderr) 345 | { 346 | const char * codes[] = { 347 | "OK", 348 | "BUSY", 349 | "NOT_SUPPORTED", 350 | "EXCEPTION", 351 | "HALT/RESUME" 352 | }; 353 | const char * msg; 354 | if (cmderr < (sizeof(codes) / sizeof(*codes))){ 355 | msg = codes[cmderr]; 356 | } else { 357 | msg = "OTHER"; 358 | } 359 | //throw std::runtime_error("Debug Abstract Command Error #" + std::to_string(cmderr) + "(" + msg + ")"); 360 | printf("ERROR: %s:%d, Debug Abstract Command Error #%d (%s)", __FILE__, __LINE__, cmderr, msg); 361 | printf("ERROR: %s:%d, Should die, but allowing simulation to continue and fail.", __FILE__, __LINE__); 362 | write(DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR); 363 | 364 | } 365 | 366 | void dtm_t::clear_chunk(uint64_t taddr, size_t len) 367 | { 368 | uint32_t prog[ram_words]; 369 | uint32_t data[data_words]; 370 | 371 | halt(current_hart); 372 | uint64_t s0 = save_reg(S0); 373 | uint64_t s1 = save_reg(S1); 374 | 375 | uint32_t command; 376 | 377 | // S0 = Addr 378 | data[0] = (uint32_t) taddr; 379 | data[1] = (uint32_t) (taddr >> 32); 380 | command = AC_ACCESS_REGISTER_TRANSFER | 381 | AC_ACCESS_REGISTER_WRITE | 382 | AC_AR_SIZE(xlen) | 383 | AC_AR_REGNO(S0); 384 | RUN_AC_OR_DIE(command, 0, 0, data, xlen/(4*8)); 385 | 386 | // S1 = Addr + len, loop until S0 = S1 387 | prog[0] = STORE(xlen, X0, S0, 0); 388 | prog[1] = ADDI(S0, S0, xlen/8); 389 | prog[2] = BNE(S0, S1, 0*4, 2*4); 390 | prog[3] = EBREAK; 391 | 392 | data[0] = (uint32_t) (taddr + len); 393 | data[1] = (uint32_t) ((taddr + len) >> 32); 394 | command = AC_ACCESS_REGISTER_TRANSFER | 395 | AC_ACCESS_REGISTER_WRITE | 396 | AC_AR_SIZE(xlen) | 397 | AC_AR_REGNO(S1) | 398 | AC_ACCESS_REGISTER_POSTEXEC; 399 | RUN_AC_OR_DIE(command, prog, 4, data, xlen/(4*8)); 400 | 401 | restore_reg(S0, s0); 402 | restore_reg(S1, s1); 403 | 404 | resume(current_hart); 405 | } 406 | 407 | uint64_t dtm_t::write_csr(unsigned which, uint64_t data) 408 | { 409 | return modify_csr(which, data, WRITE); 410 | } 411 | 412 | uint64_t dtm_t::set_csr(unsigned which, uint64_t data) 413 | { 414 | return modify_csr(which, data, SET); 415 | } 416 | 417 | uint64_t dtm_t::clear_csr(unsigned which, uint64_t data) 418 | { 419 | return modify_csr(which, data, CLEAR); 420 | } 421 | 422 | uint64_t dtm_t::read_csr(unsigned which) 423 | { 424 | return set_csr(which, 0); 425 | } 426 | 427 | uint64_t dtm_t::modify_csr(unsigned which, uint64_t data, uint32_t type) 428 | { 429 | halt(current_hart); 430 | 431 | // This code just uses DSCRATCH to save S0 432 | // and data_base to do the transfer so we don't 433 | // need to run more commands to save and restore 434 | // S0. 435 | uint32_t prog[] = { 436 | CSRRx(WRITE, S0, CSR_DSCRATCH, S0), 437 | LOAD(xlen, S0, X0, data_base), 438 | CSRRx(type, S0, which, S0), 439 | STORE(xlen, S0, X0, data_base), 440 | CSRRx(WRITE, S0, CSR_DSCRATCH, S0), 441 | EBREAK 442 | }; 443 | 444 | //TODO: Use transfer = 0. For now both HW and OpenOCD 445 | // ignore transfer bit, so use "store to X0" NOOP. 446 | // We sort of need this anyway because run_abstract_command 447 | // needs the DATA to be written so may as well use the WRITE flag. 448 | 449 | uint32_t adata[] = {(uint32_t) data, 450 | (uint32_t) (data >> 32)}; 451 | 452 | uint32_t command = AC_ACCESS_REGISTER_POSTEXEC | 453 | AC_ACCESS_REGISTER_TRANSFER | 454 | AC_ACCESS_REGISTER_WRITE | 455 | AC_AR_SIZE(xlen) | 456 | AC_AR_REGNO(X0); 457 | 458 | RUN_AC_OR_DIE(command, prog, sizeof(prog) / sizeof(*prog), adata, xlen/(4*8)); 459 | 460 | uint64_t res = read(DMI_DATA0);//adata[0]; 461 | if (xlen == 64) 462 | res |= read(DMI_DATA0 + 1);//((uint64_t) adata[1]) << 32; 463 | 464 | resume(current_hart); 465 | return res; 466 | } 467 | 468 | size_t dtm_t::chunk_max_size() 469 | { 470 | // Arbitrary choice. 4k Page size seems reasonable. 471 | return 4096; 472 | } 473 | 474 | uint32_t dtm_t::get_xlen() 475 | { 476 | // Attempt to read S0 to find out what size it is. 477 | // You could also attempt to run code, but you need to save registers 478 | // to do that anyway. If what you really want to do is figure out 479 | // the size of S0 so you can save it later, then do that. 480 | uint32_t command = AC_ACCESS_REGISTER_TRANSFER | AC_AR_REGNO(S0); 481 | uint32_t cmderr; 482 | 483 | const uint32_t prog[] = {}; 484 | uint32_t data[] = {}; 485 | 486 | cmderr = run_abstract_command(command | AC_AR_SIZE(128), prog, 0, data, 0); 487 | if (cmderr == 0){ 488 | throw std::runtime_error("FESVR DTM Does not support 128-bit"); 489 | abort(); 490 | return 128; 491 | } 492 | write(DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR); 493 | 494 | cmderr = run_abstract_command(command | AC_AR_SIZE(64), prog, 0, data, 0); 495 | if (cmderr == 0){ 496 | return 64; 497 | } 498 | write(DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR); 499 | 500 | cmderr = run_abstract_command(command | AC_AR_SIZE(32), prog, 0, data, 0); 501 | if (cmderr == 0){ 502 | return 32; 503 | } 504 | 505 | throw std::runtime_error("FESVR DTM can't determine XLEN. Aborting"); 506 | } 507 | 508 | void dtm_t::fence_i() 509 | { 510 | halt(current_hart); 511 | 512 | const uint32_t prog[] = { 513 | FENCE_I, 514 | EBREAK 515 | }; 516 | 517 | //TODO: Use the transfer = 0. 518 | uint32_t command = AC_ACCESS_REGISTER_POSTEXEC | 519 | AC_ACCESS_REGISTER_TRANSFER | 520 | AC_ACCESS_REGISTER_WRITE | 521 | AC_AR_SIZE(xlen) | 522 | AC_AR_REGNO(X0); 523 | 524 | RUN_AC_OR_DIE(command, prog, sizeof(prog)/sizeof(*prog), 0, 0); 525 | 526 | resume(current_hart); 527 | 528 | } 529 | 530 | void host_thread_main(void* arg) 531 | { 532 | ((dtm_t*)arg)->producer_thread(); 533 | } 534 | 535 | void dtm_t::reset() 536 | { 537 | for (int hartsel = 0; hartsel < num_harts; hartsel ++ ){ 538 | select_hart(hartsel); 539 | // this command also does a halt and resume 540 | fence_i(); 541 | // after this command, the hart will run from _start. 542 | write_csr(0x7b1, get_entry_point()); 543 | } 544 | // In theory any hart can handle the memory accesses, 545 | // this will enforce that hart 0 handles them. 546 | select_hart(0); 547 | read(DMI_DMSTATUS); 548 | } 549 | 550 | void dtm_t::idle() 551 | { 552 | for (int idle_cycles = 0; idle_cycles < max_idle_cycles; idle_cycles++) 553 | nop(); 554 | } 555 | 556 | void dtm_t::producer_thread() 557 | { 558 | // Learn about the Debug Module and assert things we 559 | // depend on in this code. 560 | 561 | // These are checked every time we run an abstract command. 562 | uint32_t abstractcs = read(DMI_ABSTRACTCS); 563 | ram_words = get_field(abstractcs, DMI_ABSTRACTCS_PROGSIZE); 564 | data_words = get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); 565 | 566 | // These things are only needed for the 'modify_csr' function. 567 | // That could be re-written to not use these at some performance 568 | // overhead. 569 | uint32_t hartinfo = read(DMI_HARTINFO); 570 | assert(get_field(hartinfo, DMI_HARTINFO_NSCRATCH) > 0); 571 | assert(get_field(hartinfo, DMI_HARTINFO_DATAACCESS)); 572 | 573 | data_base = get_field(hartinfo, DMI_HARTINFO_DATAADDR); 574 | 575 | // Enable the debugger. 576 | write(DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE); 577 | 578 | num_harts = enumerate_harts(); 579 | halt(0); 580 | // Note: We don't support systems with heterogeneous XLEN. 581 | // It's possible to do this at the cost of extra cycles. 582 | xlen = get_xlen(); 583 | resume(0); 584 | 585 | running = true; 586 | 587 | htif_t::run(); 588 | 589 | while (true) 590 | nop(); 591 | } 592 | 593 | void dtm_t::start_host_thread() 594 | { 595 | req_wait = false; 596 | resp_wait = false; 597 | 598 | target = context_t::current(); 599 | host.init(host_thread_main, this); 600 | host.switch_to(); 601 | } 602 | 603 | dtm_t::dtm_t(int argc, char** argv) 604 | : htif_t(argc, argv), running(false) 605 | { 606 | start_host_thread(); 607 | } 608 | 609 | dtm_t::~dtm_t() 610 | { 611 | } 612 | 613 | void dtm_t::tick( 614 | bool req_ready, 615 | bool resp_valid, 616 | resp resp_bits) 617 | { 618 | if (!resp_wait) { 619 | if (!req_wait) { 620 | req_wait = true; 621 | } else if (req_ready) { 622 | req_wait = false; 623 | resp_wait = true; 624 | } 625 | } 626 | 627 | if (resp_valid) { 628 | assert(resp_wait); 629 | resp_wait = false; 630 | 631 | resp_buf = resp_bits; 632 | // update the target with the current context 633 | target = context_t::current(); 634 | host.switch_to(); 635 | } 636 | } 637 | 638 | void dtm_t::return_resp(resp resp_bits){ 639 | resp_buf = resp_bits; 640 | target = context_t::current(); 641 | host.switch_to(); 642 | } 643 | -------------------------------------------------------------------------------- /fesvr/dtm.h: -------------------------------------------------------------------------------- 1 | #ifndef _ROCKET_DTM_H 2 | #define _ROCKET_DTM_H 3 | 4 | #include "htif.h" 5 | #include "context.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | // abstract debug transport module 14 | class dtm_t : public htif_t 15 | { 16 | public: 17 | dtm_t(int argc, char**argv); 18 | ~dtm_t(); 19 | 20 | struct req { 21 | uint32_t addr; 22 | uint32_t op; 23 | uint32_t data; 24 | }; 25 | 26 | struct resp { 27 | uint32_t resp; 28 | uint32_t data; 29 | }; 30 | 31 | void tick( 32 | bool req_ready, 33 | bool resp_valid, 34 | resp resp_bits 35 | ); 36 | // Akin to tick, but the target thread returns a response on every invocation 37 | void return_resp( 38 | resp resp_bits 39 | ); 40 | 41 | 42 | bool req_valid() { return req_wait; } 43 | req req_bits() { return req_buf; } 44 | bool resp_ready() { return true; } 45 | 46 | uint32_t read(uint32_t addr); 47 | uint32_t write(uint32_t addr, uint32_t data); 48 | void nop(); 49 | 50 | uint64_t read_csr(unsigned which); 51 | uint64_t write_csr(unsigned which, uint64_t data); 52 | uint64_t clear_csr(unsigned which, uint64_t data); 53 | uint64_t set_csr(unsigned which, uint64_t data); 54 | void fence_i(); 55 | 56 | void producer_thread(); 57 | 58 | protected: 59 | virtual void read_chunk(addr_t taddr, size_t len, void* dst) override; 60 | virtual void write_chunk(addr_t taddr, size_t len, const void* src) override; 61 | virtual void clear_chunk(addr_t taddr, size_t len) override; 62 | virtual size_t chunk_align() override; 63 | virtual size_t chunk_max_size() override; 64 | virtual void reset() override; 65 | virtual void idle() override; 66 | 67 | private: 68 | context_t host; 69 | context_t* target; 70 | pthread_t producer; 71 | sem_t req_produce; 72 | sem_t req_consume; 73 | sem_t resp_produce; 74 | sem_t resp_consume; 75 | req req_buf; 76 | resp resp_buf; 77 | bool running; 78 | 79 | uint32_t run_abstract_command(uint32_t command, const uint32_t program[], size_t program_n, 80 | uint32_t data[], size_t data_n); 81 | 82 | void die(uint32_t cmderr); 83 | void halt(int); 84 | int enumerate_harts(); 85 | void select_hart(int); 86 | void resume(int); 87 | uint64_t save_reg(unsigned regno); 88 | void restore_reg(unsigned regno, uint64_t val); 89 | 90 | uint64_t modify_csr(unsigned which, uint64_t data, uint32_t type); 91 | 92 | bool req_wait; 93 | bool resp_wait; 94 | uint32_t data_base; 95 | 96 | uint32_t xlen; 97 | 98 | static const int max_idle_cycles = 10000; 99 | 100 | size_t ram_words; 101 | size_t data_words; 102 | int num_harts; 103 | int current_hart; 104 | 105 | uint32_t get_xlen(); 106 | uint32_t do_command(dtm_t::req r); 107 | 108 | void parse_args(const std::vector& args); 109 | void register_devices(); 110 | void start_host_thread(); 111 | 112 | friend class memif_t; 113 | }; 114 | 115 | #endif 116 | -------------------------------------------------------------------------------- /fesvr/dummy.cc: -------------------------------------------------------------------------------- 1 | // See LICENSE for license details. 2 | 3 | // help out poor, C-centric autoconf 4 | extern "C" void libfesvr_is_present() {} 5 | -------------------------------------------------------------------------------- /fesvr/elf.h: -------------------------------------------------------------------------------- 1 | // See LICENSE for details. 2 | 3 | #ifndef _ELF_H 4 | #define _ELF_H 5 | 6 | #include 7 | 8 | #define IS_ELF(hdr) \ 9 | ((hdr).e_ident[0] == 0x7f && (hdr).e_ident[1] == 'E' && \ 10 | (hdr).e_ident[2] == 'L' && (hdr).e_ident[3] == 'F') 11 | 12 | #define IS_ELF32(hdr) (IS_ELF(hdr) && (hdr).e_ident[4] == 1) 13 | #define IS_ELF64(hdr) (IS_ELF(hdr) && (hdr).e_ident[4] == 2) 14 | 15 | #define PT_LOAD 1 16 | 17 | #define SHT_NOBITS 8 18 | 19 | typedef struct { 20 | uint8_t e_ident[16]; 21 | uint16_t e_type; 22 | uint16_t e_machine; 23 | uint32_t e_version; 24 | uint32_t e_entry; 25 | uint32_t e_phoff; 26 | uint32_t e_shoff; 27 | uint32_t e_flags; 28 | uint16_t e_ehsize; 29 | uint16_t e_phentsize; 30 | uint16_t e_phnum; 31 | uint16_t e_shentsize; 32 | uint16_t e_shnum; 33 | uint16_t e_shstrndx; 34 | } Elf32_Ehdr; 35 | 36 | typedef struct { 37 | uint32_t sh_name; 38 | uint32_t sh_type; 39 | uint32_t sh_flags; 40 | uint32_t sh_addr; 41 | uint32_t sh_offset; 42 | uint32_t sh_size; 43 | uint32_t sh_link; 44 | uint32_t sh_info; 45 | uint32_t sh_addralign; 46 | uint32_t sh_entsize; 47 | } Elf32_Shdr; 48 | 49 | typedef struct 50 | { 51 | uint32_t p_type; 52 | uint32_t p_offset; 53 | uint32_t p_vaddr; 54 | uint32_t p_paddr; 55 | uint32_t p_filesz; 56 | uint32_t p_memsz; 57 | uint32_t p_flags; 58 | uint32_t p_align; 59 | } Elf32_Phdr; 60 | 61 | typedef struct 62 | { 63 | uint32_t st_name; 64 | uint32_t st_value; 65 | uint32_t st_size; 66 | uint8_t st_info; 67 | uint8_t st_other; 68 | uint16_t st_shndx; 69 | } Elf32_Sym; 70 | 71 | typedef struct { 72 | uint8_t e_ident[16]; 73 | uint16_t e_type; 74 | uint16_t e_machine; 75 | uint32_t e_version; 76 | uint64_t e_entry; 77 | uint64_t e_phoff; 78 | uint64_t e_shoff; 79 | uint32_t e_flags; 80 | uint16_t e_ehsize; 81 | uint16_t e_phentsize; 82 | uint16_t e_phnum; 83 | uint16_t e_shentsize; 84 | uint16_t e_shnum; 85 | uint16_t e_shstrndx; 86 | } Elf64_Ehdr; 87 | 88 | typedef struct { 89 | uint32_t sh_name; 90 | uint32_t sh_type; 91 | uint64_t sh_flags; 92 | uint64_t sh_addr; 93 | uint64_t sh_offset; 94 | uint64_t sh_size; 95 | uint32_t sh_link; 96 | uint32_t sh_info; 97 | uint64_t sh_addralign; 98 | uint64_t sh_entsize; 99 | } Elf64_Shdr; 100 | 101 | typedef struct { 102 | uint32_t p_type; 103 | uint32_t p_flags; 104 | uint64_t p_offset; 105 | uint64_t p_vaddr; 106 | uint64_t p_paddr; 107 | uint64_t p_filesz; 108 | uint64_t p_memsz; 109 | uint64_t p_align; 110 | } Elf64_Phdr; 111 | 112 | typedef struct { 113 | uint32_t st_name; 114 | uint8_t st_info; 115 | uint8_t st_other; 116 | uint16_t st_shndx; 117 | uint64_t st_value; 118 | uint64_t st_size; 119 | } Elf64_Sym; 120 | 121 | #endif 122 | -------------------------------------------------------------------------------- /fesvr/elf2hex.cc: -------------------------------------------------------------------------------- 1 | // See LICENSE for license details. 2 | 3 | #include 4 | #include "htif_hexwriter.h" 5 | #include "memif.h" 6 | #include "elfloader.h" 7 | 8 | int main(int argc, char** argv) 9 | { 10 | if(argc < 4 || argc > 5) 11 | { 12 | std::cerr << "Usage: " << argv[0] << " [base]" << std::endl; 13 | return 1; 14 | } 15 | 16 | unsigned width = atoi(argv[1]); 17 | if(width == 0 || (width & (width-1))) 18 | { 19 | std::cerr << "width must be a power of 2" << std::endl; 20 | return 1; 21 | } 22 | 23 | unsigned long long int base = 0; 24 | if(argc==5) { 25 | base = atoll(argv[4]); 26 | if(base & (width-1)) 27 | { 28 | std::cerr << "base must be divisible by width" << std::endl; 29 | return 1; 30 | } 31 | } 32 | 33 | unsigned depth = atoi(argv[2]); 34 | if(depth == 0 || (depth & (depth-1))) 35 | { 36 | std::cerr << "depth must be a power of 2" << std::endl; 37 | return 1; 38 | } 39 | 40 | htif_hexwriter_t htif(base, width, depth); 41 | memif_t memif(&htif); 42 | reg_t entry; 43 | load_elf(argv[3], &memif, &entry); 44 | std::cout << htif; 45 | 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /fesvr/elfloader.cc: -------------------------------------------------------------------------------- 1 | // See LICENSE for license details. 2 | 3 | #include "elf.h" 4 | #include "memif.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | std::map load_elf(const char* fn, memif_t* memif, reg_t* entry) 18 | { 19 | int fd = open(fn, O_RDONLY); 20 | struct stat s; 21 | assert(fd != -1); 22 | if (fstat(fd, &s) < 0) 23 | abort(); 24 | size_t size = s.st_size; 25 | 26 | char* buf = (char*)mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); 27 | assert(buf != MAP_FAILED); 28 | close(fd); 29 | 30 | assert(size >= sizeof(Elf64_Ehdr)); 31 | const Elf64_Ehdr* eh64 = (const Elf64_Ehdr*)buf; 32 | assert(IS_ELF32(*eh64) || IS_ELF64(*eh64)); 33 | 34 | std::vector zeros; 35 | std::map symbols; 36 | 37 | #define LOAD_ELF(ehdr_t, phdr_t, shdr_t, sym_t) do { \ 38 | ehdr_t* eh = (ehdr_t*)buf; \ 39 | phdr_t* ph = (phdr_t*)(buf + eh->e_phoff); \ 40 | *entry = eh->e_entry; \ 41 | assert(size >= eh->e_phoff + eh->e_phnum*sizeof(*ph)); \ 42 | for (unsigned i = 0; i < eh->e_phnum; i++) { \ 43 | if(ph[i].p_type == PT_LOAD && ph[i].p_memsz) { \ 44 | if (ph[i].p_filesz) { \ 45 | assert(size >= ph[i].p_offset + ph[i].p_filesz); \ 46 | memif->write(ph[i].p_paddr, ph[i].p_filesz, (uint8_t*)buf + ph[i].p_offset); \ 47 | } \ 48 | zeros.resize(ph[i].p_memsz - ph[i].p_filesz); \ 49 | memif->write(ph[i].p_paddr + ph[i].p_filesz, ph[i].p_memsz - ph[i].p_filesz, &zeros[0]); \ 50 | } \ 51 | } \ 52 | shdr_t* sh = (shdr_t*)(buf + eh->e_shoff); \ 53 | assert(size >= eh->e_shoff + eh->e_shnum*sizeof(*sh)); \ 54 | assert(eh->e_shstrndx < eh->e_shnum); \ 55 | assert(size >= sh[eh->e_shstrndx].sh_offset + sh[eh->e_shstrndx].sh_size); \ 56 | char *shstrtab = buf + sh[eh->e_shstrndx].sh_offset; \ 57 | unsigned strtabidx = 0, symtabidx = 0; \ 58 | for (unsigned i = 0; i < eh->e_shnum; i++) { \ 59 | unsigned max_len = sh[eh->e_shstrndx].sh_size - sh[i].sh_name; \ 60 | assert(sh[i].sh_name < sh[eh->e_shstrndx].sh_size); \ 61 | assert(strnlen(shstrtab + sh[i].sh_name, max_len) < max_len); \ 62 | if (sh[i].sh_type & SHT_NOBITS) continue; \ 63 | assert(size >= sh[i].sh_offset + sh[i].sh_size); \ 64 | if (strcmp(shstrtab + sh[i].sh_name, ".strtab") == 0) \ 65 | strtabidx = i; \ 66 | if (strcmp(shstrtab + sh[i].sh_name, ".symtab") == 0) \ 67 | symtabidx = i; \ 68 | } \ 69 | if (strtabidx && symtabidx) { \ 70 | char* strtab = buf + sh[strtabidx].sh_offset; \ 71 | sym_t* sym = (sym_t*)(buf + sh[symtabidx].sh_offset); \ 72 | for (unsigned i = 0; i < sh[symtabidx].sh_size/sizeof(sym_t); i++) { \ 73 | unsigned max_len = sh[strtabidx].sh_size - sym[i].st_name; \ 74 | assert(sym[i].st_name < sh[strtabidx].sh_size); \ 75 | assert(strnlen(strtab + sym[i].st_name, max_len) < max_len); \ 76 | symbols[strtab + sym[i].st_name] = sym[i].st_value; \ 77 | } \ 78 | } \ 79 | } while(0) 80 | 81 | if (IS_ELF32(*eh64)) 82 | LOAD_ELF(Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Sym); 83 | else 84 | LOAD_ELF(Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Sym); 85 | 86 | munmap(buf, size); 87 | 88 | return symbols; 89 | } 90 | -------------------------------------------------------------------------------- /fesvr/elfloader.h: -------------------------------------------------------------------------------- 1 | // See LICENSE for license details. 2 | 3 | #ifndef _ELFLOADER_H 4 | #define _ELFLOADER_H 5 | 6 | #include "elf.h" 7 | #include 8 | #include 9 | 10 | class memif_t; 11 | std::map load_elf(const char* fn, memif_t* memif, reg_t* entry); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /fesvr/fesvr.ac: -------------------------------------------------------------------------------- 1 | AC_CHECK_LIB(pthread, pthread_create, [], [AC_MSG_ERROR([libpthread is required])]) 2 | -------------------------------------------------------------------------------- /fesvr/fesvr.mk.in: -------------------------------------------------------------------------------- 1 | fesvr_hdrs = \ 2 | elf.h \ 3 | elfloader.h \ 4 | htif.h \ 5 | dtm.h \ 6 | memif.h \ 7 | syscall.h \ 8 | context.h \ 9 | htif_pthread.h \ 10 | htif_hexwriter.h \ 11 | option_parser.h \ 12 | term.h \ 13 | device.h \ 14 | rfb.h \ 15 | tsi.h \ 16 | 17 | fesvr_srcs = \ 18 | elfloader.cc \ 19 | htif.cc \ 20 | memif.cc \ 21 | dtm.cc \ 22 | syscall.cc \ 23 | device.cc \ 24 | rfb.cc \ 25 | context.cc \ 26 | htif_pthread.cc \ 27 | htif_hexwriter.cc \ 28 | dummy.cc \ 29 | option_parser.cc \ 30 | term.cc \ 31 | tsi.cc \ 32 | 33 | fesvr_install_prog_srcs = \ 34 | elf2hex.cc \ 35 | -------------------------------------------------------------------------------- /fesvr/fesvr.pc.in: -------------------------------------------------------------------------------- 1 | #========================================================================= 2 | # Modular C++ Build System Subproject Package Config 3 | #========================================================================= 4 | # Please read the documenation in 'mcppbs-uguide.txt' for more details 5 | # on how the Modular C++ Build System works. 6 | 7 | #------------------------------------------------------------------------- 8 | # Generic variables 9 | #------------------------------------------------------------------------- 10 | 11 | prefix=@prefix@ 12 | include_dir=${prefix}/include/fesvr 13 | lib_dir=${prefix}/lib 14 | 15 | #------------------------------------------------------------------------- 16 | # Keywords 17 | #------------------------------------------------------------------------- 18 | 19 | Name : fesvr 20 | Version : @PACKAGE_VERSION@ 21 | Description : Frontend Server C/C++ API 22 | Requires : @fesvr_pkcdeps@ 23 | Cflags : -I${include_dir} @CPPFLAGS@ @fesvr_extra_cppflags@ 24 | Libs : -L${lib_dir} @LDFLAGS@ @fesvr_extra_ldflags@ \ 25 | -lfesvr @fesvr_extra_libs@ 26 | 27 | -------------------------------------------------------------------------------- /fesvr/htif.cc: -------------------------------------------------------------------------------- 1 | // See LICENSE for license details. 2 | 3 | #include "htif.h" 4 | #include "rfb.h" 5 | #include "elfloader.h" 6 | #include "encoding.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | /* Attempt to determine the execution prefix automatically. autoconf 20 | * sets PREFIX, and pconfigure sets __PCONFIGURE__PREFIX. */ 21 | #if !defined(PREFIX) && defined(__PCONFIGURE__PREFIX) 22 | # define PREFIX __PCONFIGURE__PREFIX 23 | #endif 24 | 25 | #ifndef TARGET_ARCH 26 | # define TARGET_ARCH "riscv64-unknown-elf" 27 | #endif 28 | 29 | #ifndef TARGET_DIR 30 | # define TARGET_DIR "/" TARGET_ARCH "/bin/" 31 | #endif 32 | 33 | static volatile bool signal_exit = false; 34 | static void handle_signal(int sig) 35 | { 36 | if (sig == SIGABRT || signal_exit) // someone set up us the bomb! 37 | exit(-1); 38 | signal_exit = true; 39 | signal(sig, &handle_signal); 40 | } 41 | 42 | htif_t::htif_t() 43 | : mem(this), entry(DRAM_BASE), sig_addr(0), sig_len(0), 44 | tohost_addr(0), fromhost_addr(0), exitcode(0), stopped(false), 45 | syscall_proxy(this) 46 | { 47 | signal(SIGINT, &handle_signal); 48 | signal(SIGTERM, &handle_signal); 49 | signal(SIGABRT, &handle_signal); // we still want to call static destructors 50 | } 51 | 52 | htif_t::htif_t(int argc, char** argv) : htif_t() 53 | { 54 | parse_arguments(argc, argv); 55 | register_devices(); 56 | } 57 | 58 | htif_t::htif_t(const std::vector& args) : htif_t() 59 | { 60 | int argc = args.size() + 1; 61 | char * argv[argc]; 62 | argv[0] = (char *) "htif"; 63 | for (unsigned int i = 0; i < args.size(); i++) { 64 | argv[i+1] = (char *) args[i].c_str(); 65 | } 66 | 67 | parse_arguments(argc, argv); 68 | register_devices(); 69 | } 70 | 71 | htif_t::~htif_t() 72 | { 73 | for (auto d : dynamic_devices) 74 | delete d; 75 | } 76 | 77 | void htif_t::start() 78 | { 79 | if (!targs.empty() && targs[0] != "none") 80 | load_program(); 81 | 82 | reset(); 83 | } 84 | 85 | void htif_t::load_program() 86 | { 87 | std::string path; 88 | if (access(targs[0].c_str(), F_OK) == 0) 89 | path = targs[0]; 90 | else if (targs[0].find('/') == std::string::npos) 91 | { 92 | std::string test_path = PREFIX TARGET_DIR + targs[0]; 93 | if (access(test_path.c_str(), F_OK) == 0) 94 | path = test_path; 95 | } 96 | 97 | if (path.empty()) 98 | throw std::runtime_error( 99 | "could not open " + targs[0] + 100 | " (did you misspell it? If VCS, did you forget +permissive/+permissive-off?)"); 101 | 102 | // temporarily construct a memory interface that skips writing bytes 103 | // that have already been preloaded through a sideband 104 | class preload_aware_memif_t : public memif_t { 105 | public: 106 | preload_aware_memif_t(htif_t* htif) : memif_t(htif), htif(htif) {} 107 | 108 | void write(addr_t taddr, size_t len, const void* src) override 109 | { 110 | if (!htif->is_address_preloaded(taddr, len)) 111 | memif_t::write(taddr, len, src); 112 | } 113 | 114 | private: 115 | htif_t* htif; 116 | } preload_aware_memif(this); 117 | 118 | std::map symbols = load_elf(path.c_str(), &preload_aware_memif, &entry); 119 | 120 | if (symbols.count("tohost") && symbols.count("fromhost")) { 121 | tohost_addr = symbols["tohost"]; 122 | fromhost_addr = symbols["fromhost"]; 123 | } else { 124 | fprintf(stderr, "warning: tohost and fromhost symbols not in ELF; can't communicate with target\n"); 125 | } 126 | 127 | // detect torture tests so we can print the memory signature at the end 128 | if (symbols.count("begin_signature") && symbols.count("end_signature")) 129 | { 130 | sig_addr = symbols["begin_signature"]; 131 | sig_len = symbols["end_signature"] - sig_addr; 132 | } 133 | } 134 | 135 | void htif_t::stop() 136 | { 137 | if (!sig_file.empty() && sig_len) // print final torture test signature 138 | { 139 | std::vector buf(sig_len); 140 | mem.read(sig_addr, sig_len, &buf[0]); 141 | 142 | std::ofstream sigs(sig_file); 143 | assert(sigs && "can't open signature file!"); 144 | sigs << std::setfill('0') << std::hex; 145 | 146 | const addr_t incr = 16; 147 | assert(sig_len % incr == 0); 148 | for (addr_t i = 0; i < sig_len; i += incr) 149 | { 150 | for (addr_t j = incr; j > 0; j--) 151 | sigs << std::setw(2) << (uint16_t)buf[i+j-1]; 152 | sigs << '\n'; 153 | } 154 | 155 | sigs.close(); 156 | } 157 | 158 | stopped = true; 159 | } 160 | 161 | void htif_t::clear_chunk(addr_t taddr, size_t len) 162 | { 163 | char zeros[chunk_max_size()]; 164 | memset(zeros, 0, chunk_max_size()); 165 | 166 | for (size_t pos = 0; pos < len; pos += chunk_max_size()) 167 | write_chunk(taddr + pos, std::min(len - pos, chunk_max_size()), zeros); 168 | } 169 | 170 | int htif_t::run() 171 | { 172 | start(); 173 | 174 | auto enq_func = [](std::queue* q, uint64_t x) { q->push(x); }; 175 | std::queue fromhost_queue; 176 | std::function fromhost_callback = 177 | std::bind(enq_func, &fromhost_queue, std::placeholders::_1); 178 | 179 | if (tohost_addr == 0) { 180 | while (true) 181 | idle(); 182 | } 183 | 184 | while (!signal_exit && exitcode == 0) 185 | { 186 | if (auto tohost = mem.read_uint64(tohost_addr)) { 187 | mem.write_uint64(tohost_addr, 0); 188 | command_t cmd(mem, tohost, fromhost_callback); 189 | device_list.handle_command(cmd); 190 | } else { 191 | idle(); 192 | } 193 | 194 | device_list.tick(); 195 | 196 | if (!fromhost_queue.empty() && mem.read_uint64(fromhost_addr) == 0) { 197 | mem.write_uint64(fromhost_addr, fromhost_queue.front()); 198 | fromhost_queue.pop(); 199 | } 200 | } 201 | 202 | stop(); 203 | 204 | return exit_code(); 205 | } 206 | 207 | bool htif_t::done() 208 | { 209 | return stopped; 210 | } 211 | 212 | int htif_t::exit_code() 213 | { 214 | return exitcode >> 1; 215 | } 216 | 217 | void htif_t::parse_arguments(int argc, char ** argv) 218 | { 219 | optind = 0; // reset optind as HTIF may run getopt _after_ others 220 | while (1) { 221 | static struct option long_options[] = { HTIF_LONG_OPTIONS }; 222 | int option_index = 0; 223 | int c = getopt_long(argc, argv, "-h", long_options, &option_index); 224 | 225 | if (c == -1) break; 226 | retry: 227 | switch (c) { 228 | case 'h': usage(argv[0]); 229 | throw std::invalid_argument("User quered htif_t help text"); 230 | case HTIF_LONG_OPTIONS_OPTIND: 231 | if (optarg) dynamic_devices.push_back(new rfb_t(atoi(optarg))); 232 | else dynamic_devices.push_back(new rfb_t); 233 | break; 234 | case HTIF_LONG_OPTIONS_OPTIND + 1: 235 | // [TODO] Remove once disks are supported again 236 | throw std::invalid_argument("--disk/+disk unsupported (use a ramdisk)"); 237 | dynamic_devices.push_back(new disk_t(optarg)); 238 | break; 239 | case HTIF_LONG_OPTIONS_OPTIND + 2: 240 | sig_file = optarg; 241 | break; 242 | case HTIF_LONG_OPTIONS_OPTIND + 3: 243 | syscall_proxy.set_chroot(optarg); 244 | break; 245 | case '?': 246 | if (!opterr) 247 | break; 248 | throw std::invalid_argument("Unknown argument (did you mean to enable +permissive parsing?)"); 249 | case 1: { 250 | std::string arg = optarg; 251 | if (arg == "+rfb") { 252 | c = HTIF_LONG_OPTIONS_OPTIND; 253 | optarg = nullptr; 254 | } 255 | else if (arg.find("+rfb=") == 0) { 256 | c = HTIF_LONG_OPTIONS_OPTIND; 257 | optarg = optarg + 5; 258 | } 259 | else if (arg.find("+disk=") == 0) { 260 | c = HTIF_LONG_OPTIONS_OPTIND + 1; 261 | optarg = optarg + 6; 262 | } 263 | else if (arg.find("+signature=") == 0) { 264 | c = HTIF_LONG_OPTIONS_OPTIND + 2; 265 | optarg = optarg + 11; 266 | } 267 | else if (arg.find("+chroot=") == 0) { 268 | c = HTIF_LONG_OPTIONS_OPTIND + 3; 269 | optarg = optarg + 8; 270 | } 271 | else if (arg.find("+permissive-off") == 0) { 272 | if (opterr) 273 | throw std::invalid_argument("Found +permissive-off when not parsing permissively"); 274 | opterr = 1; 275 | break; 276 | } 277 | else if (arg.find("+permissive") == 0) { 278 | if (!opterr) 279 | throw std::invalid_argument("Found +permissive when already parsing permissively"); 280 | opterr = 0; 281 | break; 282 | } 283 | else { 284 | if (!opterr) 285 | break; 286 | else { 287 | optind--; 288 | goto done_processing; 289 | } 290 | } 291 | goto retry; 292 | } 293 | } 294 | } 295 | 296 | done_processing: 297 | while (optind < argc) 298 | targs.push_back(argv[optind++]); 299 | if (!targs.size()) { 300 | usage(argv[0]); 301 | throw std::invalid_argument("No binary specified (Did you forget it? Did you forget '+permissive-off' if running with +permissive?)"); 302 | } 303 | } 304 | 305 | void htif_t::register_devices() 306 | { 307 | device_list.register_device(&syscall_proxy); 308 | device_list.register_device(&bcd); 309 | for (auto d : dynamic_devices) 310 | device_list.register_device(d); 311 | } 312 | 313 | void htif_t::usage(const char * program_name) 314 | { 315 | printf("Usage: %s [EMULATOR OPTION]... [VERILOG PLUSARG]... [HOST OPTION]... BINARY [TARGET OPTION]...\n ", 316 | program_name); 317 | fputs("\ 318 | Run a BINARY on the Rocket Chip emulator.\n\ 319 | \n\ 320 | Mandatory arguments to long options are mandatory for short options too.\n\ 321 | \n\ 322 | EMULATOR OPTIONS\n\ 323 | Consult emulator.cc if using Verilator or VCS documentation if using VCS\n\ 324 | for available options.\n\ 325 | EMUALTOR VERILOG PLUSARGS\n\ 326 | Consult generated-src*/*.plusArgs for available options\n\ 327 | ", stdout); 328 | fputs("\n" HTIF_USAGE_OPTIONS, stdout); 329 | } 330 | -------------------------------------------------------------------------------- /fesvr/htif.h: -------------------------------------------------------------------------------- 1 | // See LICENSE for license details. 2 | 3 | #ifndef __HTIF_H 4 | #define __HTIF_H 5 | 6 | #include "memif.h" 7 | #include "syscall.h" 8 | #include "device.h" 9 | #include 10 | #include 11 | 12 | class htif_t : public chunked_memif_t 13 | { 14 | public: 15 | htif_t(); 16 | htif_t(int argc, char** argv); 17 | htif_t(const std::vector& args); 18 | virtual ~htif_t(); 19 | 20 | virtual void start(); 21 | virtual void stop(); 22 | 23 | int run(); 24 | bool done(); 25 | int exit_code(); 26 | 27 | virtual memif_t& memif() { return mem; } 28 | 29 | protected: 30 | virtual void reset() = 0; 31 | 32 | virtual void read_chunk(addr_t taddr, size_t len, void* dst) = 0; 33 | virtual void write_chunk(addr_t taddr, size_t len, const void* src) = 0; 34 | virtual void clear_chunk(addr_t taddr, size_t len); 35 | 36 | virtual size_t chunk_align() = 0; 37 | virtual size_t chunk_max_size() = 0; 38 | 39 | virtual void load_program(); 40 | virtual void idle() {} 41 | 42 | const std::vector& host_args() { return hargs; } 43 | 44 | reg_t get_entry_point() { return entry; } 45 | 46 | // indicates that the initial program load can skip writing this address 47 | // range to memory, because it has already been loaded through a sideband 48 | virtual bool is_address_preloaded(addr_t taddr, size_t len) { return false; } 49 | 50 | private: 51 | void parse_arguments(int argc, char ** argv); 52 | void register_devices(); 53 | void usage(const char * program_name); 54 | 55 | memif_t mem; 56 | reg_t entry; 57 | bool writezeros; 58 | std::vector hargs; 59 | std::vector targs; 60 | std::string sig_file; 61 | addr_t sig_addr; // torture 62 | addr_t sig_len; // torture 63 | addr_t tohost_addr; 64 | addr_t fromhost_addr; 65 | int exitcode; 66 | bool stopped; 67 | 68 | device_list_t device_list; 69 | syscall_t syscall_proxy; 70 | bcd_t bcd; 71 | std::vector dynamic_devices; 72 | 73 | const std::vector& target_args() { return targs; } 74 | 75 | friend class memif_t; 76 | friend class syscall_t; 77 | }; 78 | 79 | /* Alignment guide for emulator.cc options: 80 | -x, --long-option Description with max 80 characters --------------->\n\ 81 | +plus-arg-equivalent\n\ 82 | */ 83 | #define HTIF_USAGE_OPTIONS \ 84 | "HOST OPTIONS\n\ 85 | -h, --help Display this help and exit\n\ 86 | +permissive The host will ignore any unparsed options up until\n\ 87 | +permissive-off (Only needed for VCS)\n\ 88 | +permissive-off Stop ignoring options. This is mandatory if using\n\ 89 | +permissive (Only needed for VCS)\n\ 90 | --rfb=DISPLAY Add new remote frame buffer on display DISPLAY\n\ 91 | +rfb=DISPLAY to be accessible on 5900 + DISPLAY (default = 0)\n\ 92 | --signature=FILE Write torture test signature to FILE\n\ 93 | +signature=FILE\n\ 94 | --chroot=PATH Use PATH as location of syscall-servicing binaries\n\ 95 | +chroot=PATH\n\ 96 | \n\ 97 | HOST OPTIONS (currently unsupported)\n\ 98 | --disk=DISK Add DISK device. Use a ramdisk since this isn't\n\ 99 | +disk=DISK supported\n\ 100 | \n\ 101 | TARGET (RISC-V BINARY) OPTIONS\n\ 102 | These are the options passed to the program executing on the emulated RISC-V\n\ 103 | microprocessor.\n" 104 | 105 | #define HTIF_LONG_OPTIONS_OPTIND 1024 106 | #define HTIF_LONG_OPTIONS \ 107 | {"help", no_argument, 0, 'h' }, \ 108 | {"rfb", optional_argument, 0, HTIF_LONG_OPTIONS_OPTIND }, \ 109 | {"disk", required_argument, 0, HTIF_LONG_OPTIONS_OPTIND + 1 }, \ 110 | {"signature", required_argument, 0, HTIF_LONG_OPTIONS_OPTIND + 2 }, \ 111 | {"chroot", required_argument, 0, HTIF_LONG_OPTIONS_OPTIND + 3 }, \ 112 | {0, 0, 0, 0} 113 | 114 | #endif // __HTIF_H 115 | -------------------------------------------------------------------------------- /fesvr/htif_hexwriter.cc: -------------------------------------------------------------------------------- 1 | // See LICENSE for license details. 2 | 3 | #include 4 | #include 5 | #include "htif_hexwriter.h" 6 | 7 | htif_hexwriter_t::htif_hexwriter_t(size_t b, size_t w, size_t d) 8 | : base(b), width(w), depth(d) 9 | { 10 | } 11 | 12 | void htif_hexwriter_t::read_chunk(addr_t taddr, size_t len, void* vdst) 13 | { 14 | taddr -= base; 15 | 16 | assert(len % chunk_align() == 0); 17 | assert(taddr < width*depth); 18 | assert(taddr+len <= width*depth); 19 | 20 | uint8_t* dst = (uint8_t*)vdst; 21 | while(len) 22 | { 23 | if(mem[taddr/width].size() == 0) 24 | mem[taddr/width].resize(width,0); 25 | 26 | for(size_t j = 0; j < width; j++) 27 | dst[j] = mem[taddr/width][j]; 28 | 29 | len -= width; 30 | taddr += width; 31 | dst += width; 32 | } 33 | } 34 | 35 | void htif_hexwriter_t::write_chunk(addr_t taddr, size_t len, const void* vsrc) 36 | { 37 | taddr -= base; 38 | 39 | assert(len % chunk_align() == 0); 40 | assert(taddr < width*depth); 41 | assert(taddr+len <= width*depth); 42 | 43 | const uint8_t* src = (const uint8_t*)vsrc; 44 | while(len) 45 | { 46 | if(mem[taddr/width].size() == 0) 47 | mem[taddr/width].resize(width,0); 48 | 49 | for(size_t j = 0; j < width; j++) 50 | mem[taddr/width][j] = src[j]; 51 | 52 | len -= width; 53 | taddr += width; 54 | } 55 | } 56 | 57 | std::ostream& operator<< (std::ostream& o, const htif_hexwriter_t& h) 58 | { 59 | std::ios_base::fmtflags flags = o.setf(std::ios::hex,std::ios::basefield); 60 | 61 | for(size_t addr = 0; addr < h.depth; addr++) 62 | { 63 | std::map >::const_iterator i = h.mem.find(addr); 64 | if(i == h.mem.end()) 65 | for(size_t j = 0; j < h.width; j++) 66 | o << "00"; 67 | else 68 | for(size_t j = 0; j < h.width; j++) 69 | o << ((i->second[h.width-j-1] >> 4) & 0xF) << (i->second[h.width-j-1] & 0xF); 70 | o << std::endl; 71 | } 72 | 73 | o.setf(flags); 74 | 75 | return o; 76 | } 77 | -------------------------------------------------------------------------------- /fesvr/htif_hexwriter.h: -------------------------------------------------------------------------------- 1 | // See LICENSE for license details. 2 | 3 | #ifndef __HTIF_HEXWRITER_H 4 | #define __HTIF_HEXWRITER_H 5 | 6 | #include 7 | #include 8 | #include 9 | #include "memif.h" 10 | 11 | class htif_hexwriter_t : public chunked_memif_t 12 | { 13 | public: 14 | htif_hexwriter_t(size_t b, size_t w, size_t d); 15 | 16 | protected: 17 | size_t base; 18 | size_t width; 19 | size_t depth; 20 | std::map > mem; 21 | 22 | void read_chunk(addr_t taddr, size_t len, void* dst); 23 | void write_chunk(addr_t taddr, size_t len, const void* src); 24 | void clear_chunk(addr_t taddr, size_t len) {} 25 | 26 | size_t chunk_max_size() { return width; } 27 | size_t chunk_align() { return width; } 28 | 29 | friend std::ostream& operator<< (std::ostream&, const htif_hexwriter_t&); 30 | }; 31 | 32 | #endif // __HTIF_HEXWRITER_H 33 | -------------------------------------------------------------------------------- /fesvr/htif_pthread.cc: -------------------------------------------------------------------------------- 1 | // See LICENSE for license details. 2 | 3 | #include "htif_pthread.h" 4 | #include 5 | #include 6 | 7 | void htif_pthread_t::thread_main(void* arg) 8 | { 9 | htif_pthread_t* htif = static_cast(arg); 10 | htif->run(); 11 | while (true) 12 | htif->target->switch_to(); 13 | } 14 | 15 | htif_pthread_t::htif_pthread_t(int argc, char** argv) 16 | : htif_t(argc, argv) 17 | { 18 | target = context_t::current(); 19 | host.init(thread_main, this); 20 | } 21 | 22 | htif_pthread_t::~htif_pthread_t() 23 | { 24 | } 25 | 26 | ssize_t htif_pthread_t::read(void* buf, size_t max_size) 27 | { 28 | while (th_data.size() == 0) 29 | target->switch_to(); 30 | 31 | size_t s = std::min(max_size, th_data.size()); 32 | std::copy(th_data.begin(), th_data.begin() + s, (char*)buf); 33 | th_data.erase(th_data.begin(), th_data.begin() + s); 34 | 35 | return s; 36 | } 37 | 38 | ssize_t htif_pthread_t::write(const void* buf, size_t size) 39 | { 40 | ht_data.insert(ht_data.end(), (const char*)buf, (const char*)buf + size); 41 | return size; 42 | } 43 | 44 | void htif_pthread_t::send(const void* buf, size_t size) 45 | { 46 | th_data.insert(th_data.end(), (const char*)buf, (const char*)buf + size); 47 | } 48 | 49 | void htif_pthread_t::recv(void* buf, size_t size) 50 | { 51 | while (!this->recv_nonblocking(buf, size)) 52 | ; 53 | } 54 | 55 | bool htif_pthread_t::recv_nonblocking(void* buf, size_t size) 56 | { 57 | if (ht_data.size() < size) 58 | { 59 | host.switch_to(); 60 | return false; 61 | } 62 | 63 | std::copy(ht_data.begin(), ht_data.begin() + size, (char*)buf); 64 | ht_data.erase(ht_data.begin(), ht_data.begin() + size); 65 | return true; 66 | } 67 | -------------------------------------------------------------------------------- /fesvr/htif_pthread.h: -------------------------------------------------------------------------------- 1 | // See LICENSE for license details. 2 | 3 | #ifndef _HTIF_PTHREAD_H 4 | #define _HTIF_PTHREAD_H 5 | 6 | #include "htif.h" 7 | #include "context.h" 8 | #include 9 | 10 | class htif_pthread_t : public htif_t 11 | { 12 | public: 13 | htif_pthread_t(int argc, char** argv); 14 | virtual ~htif_pthread_t(); 15 | 16 | // target inteface 17 | void send(const void* buf, size_t size); 18 | void recv(void* buf, size_t size); 19 | bool recv_nonblocking(void* buf, size_t size); 20 | 21 | protected: 22 | // host interface 23 | virtual ssize_t read(void* buf, size_t max_size); 24 | virtual ssize_t write(const void* buf, size_t size); 25 | 26 | virtual size_t chunk_align() { return 64; } 27 | virtual size_t chunk_max_size() { return 1024; } 28 | 29 | private: 30 | context_t host; 31 | context_t* target; 32 | std::deque th_data; 33 | std::deque ht_data; 34 | 35 | static void thread_main(void* htif); 36 | }; 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /fesvr/memif.cc: -------------------------------------------------------------------------------- 1 | // See LICENSE for license details. 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "memif.h" 8 | 9 | void memif_t::read(addr_t addr, size_t len, void* bytes) 10 | { 11 | size_t align = cmemif->chunk_align(); 12 | if (len && (addr & (align-1))) 13 | { 14 | size_t this_len = std::min(len, align - size_t(addr & (align-1))); 15 | uint8_t chunk[align]; 16 | 17 | cmemif->read_chunk(addr & ~(align-1), align, chunk); 18 | memcpy(bytes, chunk + (addr & (align-1)), this_len); 19 | 20 | bytes = (char*)bytes + this_len; 21 | addr += this_len; 22 | len -= this_len; 23 | } 24 | 25 | if (len & (align-1)) 26 | { 27 | size_t this_len = len & (align-1); 28 | size_t start = len - this_len; 29 | uint8_t chunk[align]; 30 | 31 | cmemif->read_chunk(addr + start, align, chunk); 32 | memcpy((char*)bytes + start, chunk, this_len); 33 | 34 | len -= this_len; 35 | } 36 | 37 | // now we're aligned 38 | for (size_t pos = 0; pos < len; pos += cmemif->chunk_max_size()) 39 | cmemif->read_chunk(addr + pos, std::min(cmemif->chunk_max_size(), len - pos), (char*)bytes + pos); 40 | } 41 | 42 | void memif_t::write(addr_t addr, size_t len, const void* bytes) 43 | { 44 | size_t align = cmemif->chunk_align(); 45 | if (len && (addr & (align-1))) 46 | { 47 | size_t this_len = std::min(len, align - size_t(addr & (align-1))); 48 | uint8_t chunk[align]; 49 | 50 | cmemif->read_chunk(addr & ~(align-1), align, chunk); 51 | memcpy(chunk + (addr & (align-1)), bytes, this_len); 52 | cmemif->write_chunk(addr & ~(align-1), align, chunk); 53 | 54 | bytes = (char*)bytes + this_len; 55 | addr += this_len; 56 | len -= this_len; 57 | } 58 | 59 | if (len & (align-1)) 60 | { 61 | size_t this_len = len & (align-1); 62 | size_t start = len - this_len; 63 | uint8_t chunk[align]; 64 | 65 | cmemif->read_chunk(addr + start, align, chunk); 66 | memcpy(chunk, (char*)bytes + start, this_len); 67 | cmemif->write_chunk(addr + start, align, chunk); 68 | 69 | len -= this_len; 70 | } 71 | 72 | // now we're aligned 73 | bool all_zero = len != 0; 74 | for (size_t i = 0; i < len; i++) 75 | all_zero &= ((const char*)bytes)[i] == 0; 76 | 77 | if (all_zero) { 78 | cmemif->clear_chunk(addr, len); 79 | } else { 80 | size_t max_chunk = cmemif->chunk_max_size(); 81 | for (size_t pos = 0; pos < len; pos += max_chunk) 82 | cmemif->write_chunk(addr + pos, std::min(max_chunk, len - pos), (char*)bytes + pos); 83 | } 84 | } 85 | 86 | #define MEMIF_READ_FUNC \ 87 | if(addr & (sizeof(val)-1)) \ 88 | throw std::runtime_error("misaligned address"); \ 89 | this->read(addr, sizeof(val), &val); \ 90 | return val 91 | 92 | #define MEMIF_WRITE_FUNC \ 93 | if(addr & (sizeof(val)-1)) \ 94 | throw std::runtime_error("misaligned address"); \ 95 | this->write(addr, sizeof(val), &val) 96 | 97 | uint8_t memif_t::read_uint8(addr_t addr) 98 | { 99 | uint8_t val; 100 | MEMIF_READ_FUNC; 101 | } 102 | 103 | int8_t memif_t::read_int8(addr_t addr) 104 | { 105 | int8_t val; 106 | MEMIF_READ_FUNC; 107 | } 108 | 109 | void memif_t::write_uint8(addr_t addr, uint8_t val) 110 | { 111 | MEMIF_WRITE_FUNC; 112 | } 113 | 114 | void memif_t::write_int8(addr_t addr, int8_t val) 115 | { 116 | MEMIF_WRITE_FUNC; 117 | } 118 | 119 | uint16_t memif_t::read_uint16(addr_t addr) 120 | { 121 | uint16_t val; 122 | MEMIF_READ_FUNC; 123 | } 124 | 125 | int16_t memif_t::read_int16(addr_t addr) 126 | { 127 | int16_t val; 128 | MEMIF_READ_FUNC; 129 | } 130 | 131 | void memif_t::write_uint16(addr_t addr, uint16_t val) 132 | { 133 | MEMIF_WRITE_FUNC; 134 | } 135 | 136 | void memif_t::write_int16(addr_t addr, int16_t val) 137 | { 138 | MEMIF_WRITE_FUNC; 139 | } 140 | 141 | uint32_t memif_t::read_uint32(addr_t addr) 142 | { 143 | uint32_t val; 144 | MEMIF_READ_FUNC; 145 | } 146 | 147 | int32_t memif_t::read_int32(addr_t addr) 148 | { 149 | int32_t val; 150 | MEMIF_READ_FUNC; 151 | } 152 | 153 | void memif_t::write_uint32(addr_t addr, uint32_t val) 154 | { 155 | MEMIF_WRITE_FUNC; 156 | } 157 | 158 | void memif_t::write_int32(addr_t addr, int32_t val) 159 | { 160 | MEMIF_WRITE_FUNC; 161 | } 162 | 163 | uint64_t memif_t::read_uint64(addr_t addr) 164 | { 165 | uint64_t val; 166 | MEMIF_READ_FUNC; 167 | } 168 | 169 | int64_t memif_t::read_int64(addr_t addr) 170 | { 171 | int64_t val; 172 | MEMIF_READ_FUNC; 173 | } 174 | 175 | void memif_t::write_uint64(addr_t addr, uint64_t val) 176 | { 177 | MEMIF_WRITE_FUNC; 178 | } 179 | 180 | void memif_t::write_int64(addr_t addr, int64_t val) 181 | { 182 | MEMIF_WRITE_FUNC; 183 | } 184 | -------------------------------------------------------------------------------- /fesvr/memif.h: -------------------------------------------------------------------------------- 1 | // See LICENSE for license details. 2 | 3 | #ifndef __MEMIF_H 4 | #define __MEMIF_H 5 | 6 | #include 7 | #include 8 | 9 | typedef uint64_t reg_t; 10 | typedef int64_t sreg_t; 11 | typedef reg_t addr_t; 12 | 13 | class chunked_memif_t 14 | { 15 | public: 16 | virtual void read_chunk(addr_t taddr, size_t len, void* dst) = 0; 17 | virtual void write_chunk(addr_t taddr, size_t len, const void* src) = 0; 18 | virtual void clear_chunk(addr_t taddr, size_t len) = 0; 19 | 20 | virtual size_t chunk_align() = 0; 21 | virtual size_t chunk_max_size() = 0; 22 | }; 23 | 24 | class memif_t 25 | { 26 | public: 27 | memif_t(chunked_memif_t* _cmemif) : cmemif(_cmemif) {} 28 | virtual ~memif_t(){} 29 | 30 | // read and write byte arrays 31 | virtual void read(addr_t addr, size_t len, void* bytes); 32 | virtual void write(addr_t addr, size_t len, const void* bytes); 33 | 34 | // read and write 8-bit words 35 | virtual uint8_t read_uint8(addr_t addr); 36 | virtual int8_t read_int8(addr_t addr); 37 | virtual void write_uint8(addr_t addr, uint8_t val); 38 | virtual void write_int8(addr_t addr, int8_t val); 39 | 40 | // read and write 16-bit words 41 | virtual uint16_t read_uint16(addr_t addr); 42 | virtual int16_t read_int16(addr_t addr); 43 | virtual void write_uint16(addr_t addr, uint16_t val); 44 | virtual void write_int16(addr_t addr, int16_t val); 45 | 46 | // read and write 32-bit words 47 | virtual uint32_t read_uint32(addr_t addr); 48 | virtual int32_t read_int32(addr_t addr); 49 | virtual void write_uint32(addr_t addr, uint32_t val); 50 | virtual void write_int32(addr_t addr, int32_t val); 51 | 52 | // read and write 64-bit words 53 | virtual uint64_t read_uint64(addr_t addr); 54 | virtual int64_t read_int64(addr_t addr); 55 | virtual void write_uint64(addr_t addr, uint64_t val); 56 | virtual void write_int64(addr_t addr, int64_t val); 57 | 58 | protected: 59 | chunked_memif_t* cmemif; 60 | }; 61 | 62 | #endif // __MEMIF_H 63 | -------------------------------------------------------------------------------- /fesvr/option_parser.cc: -------------------------------------------------------------------------------- 1 | // See LICENSE for license details. 2 | 3 | #include "option_parser.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | void option_parser_t::option(char c, const char* s, int arg, std::function action) 10 | { 11 | opts.push_back(option_t(c, s, arg, action)); 12 | } 13 | 14 | const char* const* option_parser_t::parse(const char* const* argv0) 15 | { 16 | assert(argv0); 17 | const char* const* argv = argv0 + 1; 18 | for (const char* opt; (opt = *argv) != NULL && opt[0] == '-'; argv++) 19 | { 20 | bool found = false; 21 | for (auto it = opts.begin(); !found && it != opts.end(); it++) 22 | { 23 | size_t slen = it->str ? strlen(it->str) : 0; 24 | bool chr_match = opt[1] != '-' && it->chr && opt[1] == it->chr; 25 | bool str_match = opt[1] == '-' && slen && strncmp(opt+2, it->str, slen) == 0; 26 | if (chr_match || (str_match && (opt[2+slen] == '=' || opt[2+slen] == '\0'))) 27 | { 28 | const char* optarg = 29 | chr_match ? (opt[2] ? &opt[2] : NULL) : 30 | opt[2+slen] ? &opt[3+slen] : 31 | it->arg ? *(++argv) : NULL; 32 | if (optarg && !it->arg) 33 | error("no argument allowed for option", *argv0, opt); 34 | if (!optarg && it->arg) 35 | error("argument required for option", *argv0, opt); 36 | it->func(optarg); 37 | found = true; 38 | } 39 | } 40 | if (!found) 41 | error("unrecognized option", *argv0, opt); 42 | } 43 | return argv; 44 | } 45 | 46 | void option_parser_t::error(const char* msg, const char* argv0, const char* arg) 47 | { 48 | fprintf(stderr, "%s: %s %s\n", argv0, msg, arg ? arg : ""); 49 | if (helpmsg) helpmsg(); 50 | exit(1); 51 | } 52 | -------------------------------------------------------------------------------- /fesvr/option_parser.h: -------------------------------------------------------------------------------- 1 | // See LICENSE for license details. 2 | 3 | #ifndef _OPTION_PARSER_H 4 | #define _OPTION_PARSER_H 5 | 6 | #include 7 | #include 8 | 9 | class option_parser_t 10 | { 11 | public: 12 | option_parser_t() : helpmsg(0) {} 13 | void help(void (*helpm)(void)) { helpmsg = helpm; } 14 | void option(char c, const char* s, int arg, std::function action); 15 | const char* const* parse(const char* const* argv0); 16 | private: 17 | struct option_t 18 | { 19 | char chr; 20 | const char* str; 21 | int arg; 22 | std::function func; 23 | option_t(char chr, const char* str, int arg, std::function func) 24 | : chr(chr), str(str), arg(arg), func(func) {} 25 | }; 26 | std::vector opts; 27 | void (*helpmsg)(void); 28 | void error(const char* msg, const char* argv0, const char* arg); 29 | }; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /fesvr/rfb.cc: -------------------------------------------------------------------------------- 1 | #include "rfb.h" 2 | #include "memif.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | using namespace std::placeholders; 14 | 15 | rfb_t::rfb_t(int display) 16 | : sockfd(-1), afd(-1), 17 | memif(0), addr(0), width(0), height(0), bpp(0), display(display), 18 | thread(pthread_self()), fb1(0), fb2(0), read_pos(0), 19 | lock(PTHREAD_MUTEX_INITIALIZER) 20 | { 21 | register_command(0, std::bind(&rfb_t::handle_configure, this, _1), "configure"); 22 | register_command(1, std::bind(&rfb_t::handle_set_address, this, _1), "set_address"); 23 | } 24 | 25 | void* rfb_thread_main(void* arg) 26 | { 27 | ((rfb_t*)arg)->thread_main(); 28 | return 0; 29 | } 30 | 31 | void rfb_t::thread_main() 32 | { 33 | pthread_mutex_lock(&lock); 34 | 35 | int port = 5900 + display; 36 | sockfd = socket(PF_INET, SOCK_STREAM, 0); 37 | if (sockfd < 0) 38 | throw std::runtime_error("could not acquire tcp socket"); 39 | 40 | struct sockaddr_in saddr, caddr; 41 | saddr.sin_family = AF_INET; 42 | saddr.sin_addr.s_addr = INADDR_ANY; 43 | saddr.sin_port = htons(port); 44 | if (bind(sockfd, (struct sockaddr*)&saddr, sizeof(saddr)) < 0) 45 | throw std::runtime_error("could not bind to port " + std::to_string(port)); 46 | if (listen(sockfd, 0) < 0) 47 | throw std::runtime_error("could not listen on port " + std::to_string(port)); 48 | 49 | socklen_t clen = sizeof(caddr); 50 | afd = accept(sockfd, (struct sockaddr*)&caddr, &clen); 51 | if (afd < 0) 52 | throw std::runtime_error("could not accept connection"); 53 | 54 | std::string version = "RFB 003.003\n"; 55 | write(version); 56 | if (read() != version) 57 | throw std::runtime_error("bad client version"); 58 | 59 | write(str(uint32_t(htonl(1)))); 60 | 61 | read(); // clientinit 62 | 63 | std::string serverinit; 64 | serverinit += str(uint16_t(htons(width))); 65 | serverinit += str(uint16_t(htons(height))); 66 | serverinit += pixel_format(); 67 | std::string name = "RISC-V"; 68 | serverinit += str(uint32_t(htonl(name.length()))); 69 | serverinit += name; 70 | write(serverinit); 71 | 72 | pthread_mutex_unlock(&lock); 73 | 74 | while (memif == NULL) 75 | sched_yield(); 76 | 77 | while (memif != NULL) 78 | { 79 | std::string s = read(); 80 | if (s.length() < 4) 81 | break; //throw std::runtime_error("bad command"); 82 | 83 | switch (s[0]) 84 | { 85 | case 0: set_pixel_format(s); break; 86 | case 2: set_encodings(s); break; 87 | case 3: break; 88 | } 89 | } 90 | 91 | pthread_mutex_lock(&lock); 92 | close(afd); 93 | close(sockfd); 94 | afd = -1; 95 | sockfd = -1; 96 | pthread_mutex_unlock(&lock); 97 | 98 | thread_main(); 99 | } 100 | 101 | rfb_t::~rfb_t() 102 | { 103 | memif = 0; 104 | if (!pthread_equal(pthread_self(), thread)) 105 | pthread_join(thread, 0); 106 | delete [] fb1; 107 | delete [] fb2; 108 | } 109 | 110 | void rfb_t::set_encodings(const std::string& s) 111 | { 112 | uint16_t n = htons(*(uint16_t*)&s[2]); 113 | for (size_t b = s.length(); b < 4U+4U*n; b += read().length()); 114 | } 115 | 116 | void rfb_t::set_pixel_format(const std::string& s) 117 | { 118 | if (s.length() != 20 || s.substr(4, 16) != pixel_format()) 119 | throw std::runtime_error("bad pixel format"); 120 | } 121 | 122 | void rfb_t::fb_update(const std::string& s) 123 | { 124 | std::string u; 125 | u += str(uint8_t(0)); 126 | u += str(uint8_t(0)); 127 | u += str(uint16_t(htons(1))); 128 | u += str(uint16_t(htons(0))); 129 | u += str(uint16_t(htons(0))); 130 | u += str(uint16_t(htons(width))); 131 | u += str(uint16_t(htons(height))); 132 | u += str(uint32_t(htonl(0))); 133 | u += std::string((char*)fb1, fb_bytes()); 134 | 135 | try 136 | { 137 | write(u); 138 | } 139 | catch (std::runtime_error& e) 140 | { 141 | } 142 | } 143 | 144 | void rfb_t::tick() 145 | { 146 | if (fb_bytes() == 0 || memif == NULL) 147 | return; 148 | 149 | memif->read(addr + read_pos, FB_ALIGN, const_cast(fb2 + read_pos)); 150 | read_pos = (read_pos + FB_ALIGN) % fb_bytes(); 151 | if (read_pos == 0) 152 | { 153 | std::swap(fb1, fb2); 154 | if (pthread_mutex_trylock(&lock) == 0) 155 | { 156 | fb_update(""); 157 | pthread_mutex_unlock(&lock); 158 | } 159 | } 160 | } 161 | 162 | std::string rfb_t::pixel_format() 163 | { 164 | int red_bits = 8, green_bits = 8, blue_bits = 8; 165 | int bpp = red_bits + green_bits + blue_bits; 166 | while (bpp & (bpp-1)) bpp++; 167 | 168 | std::string fmt; 169 | fmt += str(uint8_t(bpp)); 170 | fmt += str(uint8_t(red_bits + green_bits + blue_bits)); 171 | fmt += str(uint8_t(0)); // little-endian 172 | fmt += str(uint8_t(1)); // true color 173 | fmt += str(uint16_t(htons((1<> 16; 208 | 209 | bpp = cmd.payload() >> 32; 210 | if (bpp != 32) 211 | throw std::runtime_error("rfb requires 32 bpp true color"); 212 | 213 | if (fb_bytes() % FB_ALIGN != 0) 214 | throw std::runtime_error("rfb size must be a multiple of " + std::to_string(FB_ALIGN)); 215 | 216 | fb1 = new char[fb_bytes()]; 217 | fb2 = new char[fb_bytes()]; 218 | if (pthread_create(&thread, 0, rfb_thread_main, this)) 219 | throw std::runtime_error("could not create thread"); 220 | cmd.respond(1); 221 | } 222 | 223 | void rfb_t::handle_set_address(command_t cmd) 224 | { 225 | addr = cmd.payload(); 226 | if (addr % FB_ALIGN != 0) 227 | throw std::runtime_error("rfb address must be " + std::to_string(FB_ALIGN) + "-byte aligned"); 228 | memif = &cmd.memif(); 229 | cmd.respond(1); 230 | } 231 | -------------------------------------------------------------------------------- /fesvr/rfb.h: -------------------------------------------------------------------------------- 1 | #ifndef _RFB_H 2 | #define _RFB_H 3 | 4 | #include "device.h" 5 | #include "memif.h" 6 | #include 7 | 8 | // remote frame buffer 9 | class rfb_t : public device_t 10 | { 11 | public: 12 | rfb_t(int display = 0); 13 | ~rfb_t(); 14 | void tick(); 15 | std::string name() { return "RISC-V"; } 16 | const char* identity() { return "rfb"; } 17 | 18 | private: 19 | template 20 | std::string str(T x) 21 | { 22 | return std::string((char*)&x, sizeof(x)); 23 | } 24 | size_t fb_bytes() { return size_t(width) * height * bpp/8; } 25 | void thread_main(); 26 | friend void* rfb_thread_main(void*); 27 | std::string pixel_format(); 28 | void fb_update(const std::string& s); 29 | void set_encodings(const std::string& s); 30 | void set_pixel_format(const std::string& s); 31 | void write(const std::string& s); 32 | std::string read(); 33 | void handle_configure(command_t cmd); 34 | void handle_set_address(command_t cmd); 35 | 36 | int sockfd; 37 | int afd; 38 | memif_t* memif; 39 | reg_t addr; 40 | uint16_t width; 41 | uint16_t height; 42 | uint16_t bpp; 43 | int display; 44 | pthread_t thread; 45 | volatile char* volatile fb1; 46 | volatile char* volatile fb2; 47 | size_t read_pos; 48 | pthread_mutex_t lock; 49 | 50 | static const int FB_ALIGN = 256; 51 | }; 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /fesvr/syscall.cc: -------------------------------------------------------------------------------- 1 | // See LICENSE for license details. 2 | 3 | #include "syscall.h" 4 | #include "htif.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | using namespace std::placeholders; 16 | 17 | #define RISCV_AT_FDCWD -100 18 | 19 | struct riscv_stat 20 | { 21 | uint64_t dev; 22 | uint64_t ino; 23 | uint32_t mode; 24 | uint32_t nlink; 25 | uint32_t uid; 26 | uint32_t gid; 27 | uint64_t rdev; 28 | uint64_t __pad1; 29 | uint64_t size; 30 | uint32_t blksize; 31 | uint32_t __pad2; 32 | uint64_t blocks; 33 | uint64_t atime; 34 | uint64_t __pad3; 35 | uint64_t mtime; 36 | uint64_t __pad4; 37 | uint64_t ctime; 38 | uint64_t __pad5; 39 | uint32_t __unused4; 40 | uint32_t __unused5; 41 | 42 | riscv_stat(const struct stat& s) 43 | : dev(s.st_dev), ino(s.st_ino), mode(s.st_mode), nlink(s.st_nlink), 44 | uid(s.st_uid), gid(s.st_gid), rdev(s.st_rdev), __pad1(0), 45 | size(s.st_size), blksize(s.st_blksize), __pad2(0), 46 | blocks(s.st_blocks), atime(s.st_atime), __pad3(0), 47 | mtime(s.st_mtime), __pad4(0), ctime(s.st_ctime), __pad5(0), 48 | __unused4(0), __unused5(0) {} 49 | }; 50 | 51 | syscall_t::syscall_t(htif_t* htif) 52 | : htif(htif), memif(&htif->memif()), table(2048) 53 | { 54 | table[17] = &syscall_t::sys_getcwd; 55 | table[25] = &syscall_t::sys_fcntl; 56 | table[34] = &syscall_t::sys_mkdirat; 57 | table[35] = &syscall_t::sys_unlinkat; 58 | table[37] = &syscall_t::sys_linkat; 59 | table[38] = &syscall_t::sys_renameat; 60 | table[46] = &syscall_t::sys_ftruncate; 61 | table[48] = &syscall_t::sys_faccessat; 62 | table[49] = &syscall_t::sys_chdir; 63 | table[56] = &syscall_t::sys_openat; 64 | table[57] = &syscall_t::sys_close; 65 | table[62] = &syscall_t::sys_lseek; 66 | table[63] = &syscall_t::sys_read; 67 | table[64] = &syscall_t::sys_write; 68 | table[67] = &syscall_t::sys_pread; 69 | table[68] = &syscall_t::sys_pwrite; 70 | table[79] = &syscall_t::sys_fstatat; 71 | table[80] = &syscall_t::sys_fstat; 72 | table[93] = &syscall_t::sys_exit; 73 | table[1039] = &syscall_t::sys_lstat; 74 | table[2011] = &syscall_t::sys_getmainvars; 75 | 76 | register_command(0, std::bind(&syscall_t::handle_syscall, this, _1), "syscall"); 77 | 78 | int stdin_fd = dup(0), stdout_fd0 = dup(1), stdout_fd1 = dup(1); 79 | if (stdin_fd < 0 || stdout_fd0 < 0 || stdout_fd1 < 0) 80 | throw std::runtime_error("could not dup stdin/stdout"); 81 | 82 | fds.alloc(stdin_fd); // stdin -> stdin 83 | fds.alloc(stdout_fd0); // stdout -> stdout 84 | fds.alloc(stdout_fd1); // stderr -> stdout 85 | } 86 | 87 | std::string syscall_t::do_chroot(const char* fn) 88 | { 89 | if (!chroot.empty() && *fn == '/') 90 | return chroot + fn; 91 | return fn; 92 | } 93 | 94 | std::string syscall_t::undo_chroot(const char* fn) 95 | { 96 | if (chroot.empty()) 97 | return fn; 98 | if (strncmp(fn, chroot.c_str(), chroot.size()) == 0 99 | && (chroot.back() == '/' || fn[chroot.size()] == '/')) 100 | return fn + chroot.size() - (chroot.back() == '/'); 101 | return "/"; 102 | } 103 | 104 | void syscall_t::handle_syscall(command_t cmd) 105 | { 106 | if (cmd.payload() & 1) // test pass/fail 107 | { 108 | htif->exitcode = cmd.payload(); 109 | if (htif->exit_code()) 110 | std::cerr << "*** FAILED *** (tohost = " << htif->exit_code() << ")" << std::endl; 111 | return; 112 | } 113 | else // proxied system call 114 | dispatch(cmd.payload()); 115 | 116 | cmd.respond(1); 117 | } 118 | 119 | reg_t syscall_t::sys_exit(reg_t code, reg_t a1, reg_t a2, reg_t a3, reg_t a4, reg_t a5, reg_t a6) 120 | { 121 | htif->exitcode = code << 1 | 1; 122 | return 0; 123 | } 124 | 125 | static reg_t sysret_errno(sreg_t ret) 126 | { 127 | return ret == -1 ? -errno : ret; 128 | } 129 | 130 | reg_t syscall_t::sys_read(reg_t fd, reg_t pbuf, reg_t len, reg_t a3, reg_t a4, reg_t a5, reg_t a6) 131 | { 132 | std::vector buf(len); 133 | ssize_t ret = read(fds.lookup(fd), &buf[0], len); 134 | reg_t ret_errno = sysret_errno(ret); 135 | if (ret > 0) 136 | memif->write(pbuf, ret, &buf[0]); 137 | return ret_errno; 138 | } 139 | 140 | reg_t syscall_t::sys_pread(reg_t fd, reg_t pbuf, reg_t len, reg_t off, reg_t a4, reg_t a5, reg_t a6) 141 | { 142 | std::vector buf(len); 143 | ssize_t ret = pread(fds.lookup(fd), &buf[0], len, off); 144 | reg_t ret_errno = sysret_errno(ret); 145 | if (ret > 0) 146 | memif->write(pbuf, ret, &buf[0]); 147 | return ret_errno; 148 | } 149 | 150 | reg_t syscall_t::sys_write(reg_t fd, reg_t pbuf, reg_t len, reg_t a3, reg_t a4, reg_t a5, reg_t a6) 151 | { 152 | std::vector buf(len); 153 | memif->read(pbuf, len, &buf[0]); 154 | reg_t ret = sysret_errno(write(fds.lookup(fd), &buf[0], len)); 155 | return ret; 156 | } 157 | 158 | reg_t syscall_t::sys_pwrite(reg_t fd, reg_t pbuf, reg_t len, reg_t off, reg_t a4, reg_t a5, reg_t a6) 159 | { 160 | std::vector buf(len); 161 | memif->read(pbuf, len, &buf[0]); 162 | reg_t ret = sysret_errno(pwrite(fds.lookup(fd), &buf[0], len, off)); 163 | return ret; 164 | } 165 | 166 | reg_t syscall_t::sys_close(reg_t fd, reg_t a1, reg_t a2, reg_t a3, reg_t a4, reg_t a5, reg_t a6) 167 | { 168 | if (close(fds.lookup(fd)) < 0) 169 | return sysret_errno(-1); 170 | fds.dealloc(fd); 171 | return 0; 172 | } 173 | 174 | reg_t syscall_t::sys_lseek(reg_t fd, reg_t ptr, reg_t dir, reg_t a3, reg_t a4, reg_t a5, reg_t a6) 175 | { 176 | return sysret_errno(lseek(fds.lookup(fd), ptr, dir)); 177 | } 178 | 179 | reg_t syscall_t::sys_fstat(reg_t fd, reg_t pbuf, reg_t a2, reg_t a3, reg_t a4, reg_t a5, reg_t a6) 180 | { 181 | struct stat buf; 182 | reg_t ret = sysret_errno(fstat(fds.lookup(fd), &buf)); 183 | if (ret != (reg_t)-1) 184 | { 185 | riscv_stat rbuf(buf); 186 | memif->write(pbuf, sizeof(rbuf), &rbuf); 187 | } 188 | return ret; 189 | } 190 | 191 | reg_t syscall_t::sys_fcntl(reg_t fd, reg_t cmd, reg_t arg, reg_t a3, reg_t a4, reg_t a5, reg_t a6) 192 | { 193 | return sysret_errno(fcntl(fds.lookup(fd), cmd, arg)); 194 | } 195 | 196 | reg_t syscall_t::sys_ftruncate(reg_t fd, reg_t len, reg_t a2, reg_t a3, reg_t a4, reg_t a5, reg_t a6) 197 | { 198 | return sysret_errno(ftruncate(fds.lookup(fd), len)); 199 | } 200 | 201 | reg_t syscall_t::sys_lstat(reg_t pname, reg_t len, reg_t pbuf, reg_t a3, reg_t a4, reg_t a5, reg_t a6) 202 | { 203 | std::vector name(len); 204 | memif->read(pname, len, &name[0]); 205 | 206 | struct stat buf; 207 | reg_t ret = sysret_errno(lstat(do_chroot(&name[0]).c_str(), &buf)); 208 | riscv_stat rbuf(buf); 209 | if (ret != (reg_t)-1) 210 | { 211 | riscv_stat rbuf(buf); 212 | memif->write(pbuf, sizeof(rbuf), &rbuf); 213 | } 214 | return ret; 215 | } 216 | 217 | #define AT_SYSCALL(syscall, fd, name, ...) \ 218 | (syscall(fds.lookup(fd), int(fd) == RISCV_AT_FDCWD ? do_chroot(name).c_str() : (name), __VA_ARGS__)) 219 | 220 | reg_t syscall_t::sys_openat(reg_t dirfd, reg_t pname, reg_t len, reg_t flags, reg_t mode, reg_t a5, reg_t a6) 221 | { 222 | std::vector name(len); 223 | memif->read(pname, len, &name[0]); 224 | int fd = sysret_errno(AT_SYSCALL(openat, dirfd, &name[0], flags, mode)); 225 | if (fd < 0) 226 | return sysret_errno(-1); 227 | return fds.alloc(fd); 228 | } 229 | 230 | reg_t syscall_t::sys_fstatat(reg_t dirfd, reg_t pname, reg_t len, reg_t pbuf, reg_t flags, reg_t a5, reg_t a6) 231 | { 232 | std::vector name(len); 233 | memif->read(pname, len, &name[0]); 234 | 235 | struct stat buf; 236 | reg_t ret = sysret_errno(AT_SYSCALL(fstatat, dirfd, &name[0], &buf, flags)); 237 | if (ret != (reg_t)-1) 238 | { 239 | riscv_stat rbuf(buf); 240 | memif->write(pbuf, sizeof(rbuf), &rbuf); 241 | } 242 | return ret; 243 | } 244 | 245 | reg_t syscall_t::sys_faccessat(reg_t dirfd, reg_t pname, reg_t len, reg_t mode, reg_t a4, reg_t a5, reg_t a6) 246 | { 247 | std::vector name(len); 248 | memif->read(pname, len, &name[0]); 249 | return sysret_errno(AT_SYSCALL(faccessat, dirfd, &name[0], mode, 0)); 250 | } 251 | 252 | reg_t syscall_t::sys_renameat(reg_t odirfd, reg_t popath, reg_t olen, reg_t ndirfd, reg_t pnpath, reg_t nlen, reg_t a6) 253 | { 254 | std::vector opath(olen), npath(nlen); 255 | memif->read(popath, olen, &opath[0]); 256 | memif->read(pnpath, nlen, &npath[0]); 257 | return sysret_errno(renameat(fds.lookup(odirfd), int(odirfd) == RISCV_AT_FDCWD ? do_chroot(&opath[0]).c_str() : &opath[0], 258 | fds.lookup(ndirfd), int(ndirfd) == RISCV_AT_FDCWD ? do_chroot(&npath[0]).c_str() : &npath[0])); 259 | } 260 | 261 | reg_t syscall_t::sys_linkat(reg_t odirfd, reg_t poname, reg_t olen, reg_t ndirfd, reg_t pnname, reg_t nlen, reg_t flags) 262 | { 263 | std::vector oname(olen), nname(nlen); 264 | memif->read(poname, olen, &oname[0]); 265 | memif->read(pnname, nlen, &nname[0]); 266 | return sysret_errno(linkat(fds.lookup(odirfd), int(odirfd) == RISCV_AT_FDCWD ? do_chroot(&oname[0]).c_str() : &oname[0], 267 | fds.lookup(ndirfd), int(ndirfd) == RISCV_AT_FDCWD ? do_chroot(&nname[0]).c_str() : &nname[0], 268 | flags)); 269 | } 270 | 271 | reg_t syscall_t::sys_unlinkat(reg_t dirfd, reg_t pname, reg_t len, reg_t flags, reg_t a4, reg_t a5, reg_t a6) 272 | { 273 | std::vector name(len); 274 | memif->read(pname, len, &name[0]); 275 | return sysret_errno(AT_SYSCALL(unlinkat, dirfd, &name[0], flags)); 276 | } 277 | 278 | reg_t syscall_t::sys_mkdirat(reg_t dirfd, reg_t pname, reg_t len, reg_t mode, reg_t a4, reg_t a5, reg_t a6) 279 | { 280 | std::vector name(len); 281 | memif->read(pname, len, &name[0]); 282 | return sysret_errno(AT_SYSCALL(mkdirat, dirfd, &name[0], mode)); 283 | } 284 | 285 | reg_t syscall_t::sys_getcwd(reg_t pbuf, reg_t size, reg_t a2, reg_t a3, reg_t a4, reg_t a5, reg_t a6) 286 | { 287 | std::vector buf(size); 288 | char* ret = getcwd(&buf[0], size); 289 | if (ret == NULL) 290 | return sysret_errno(-1); 291 | std::string tmp = undo_chroot(&buf[0]); 292 | if (size <= tmp.size()) 293 | return -ENOMEM; 294 | memif->write(pbuf, tmp.size() + 1, &tmp[0]); 295 | return tmp.size() + 1; 296 | } 297 | 298 | reg_t syscall_t::sys_getmainvars(reg_t pbuf, reg_t limit, reg_t a2, reg_t a3, reg_t a4, reg_t a5, reg_t a6) 299 | { 300 | std::vector args = htif->target_args(); 301 | std::vector words(args.size() + 3); 302 | words[0] = args.size(); 303 | words[args.size()+1] = 0; // argv[argc] = NULL 304 | words[args.size()+2] = 0; // envp[0] = NULL 305 | 306 | size_t sz = (args.size() + 3) * sizeof(words[0]); 307 | for (size_t i = 0; i < args.size(); i++) 308 | { 309 | words[i+1] = sz + pbuf; 310 | sz += args[i].length() + 1; 311 | } 312 | 313 | std::vector bytes(sz); 314 | memcpy(&bytes[0], &words[0], sizeof(words[0]) * words.size()); 315 | for (size_t i = 0; i < args.size(); i++) 316 | strcpy(&bytes[words[i+1] - pbuf], args[i].c_str()); 317 | 318 | if (bytes.size() > limit) 319 | return -ENOMEM; 320 | 321 | memif->write(pbuf, bytes.size(), &bytes[0]); 322 | return 0; 323 | } 324 | 325 | reg_t syscall_t::sys_chdir(reg_t path, reg_t a1, reg_t a2, reg_t a3, reg_t a4, reg_t a5, reg_t a6) 326 | { 327 | size_t size = 0; 328 | while (memif->read_uint8(path + size++)) 329 | ; 330 | std::vector buf(size); 331 | for (size_t offset = 0;; offset++) 332 | { 333 | buf[offset] = memif->read_uint8(path + offset); 334 | if (!buf[offset]) 335 | break; 336 | } 337 | return sysret_errno(chdir(buf.data())); 338 | } 339 | 340 | void syscall_t::dispatch(reg_t mm) 341 | { 342 | reg_t magicmem[8]; 343 | memif->read(mm, sizeof(magicmem), magicmem); 344 | 345 | reg_t n = magicmem[0]; 346 | if (n >= table.size() || !table[n]) 347 | throw std::runtime_error("bad syscall #" + std::to_string(n)); 348 | 349 | magicmem[0] = (this->*table[n])(magicmem[1], magicmem[2], magicmem[3], magicmem[4], magicmem[5], magicmem[6], magicmem[7]); 350 | 351 | memif->write(mm, sizeof(magicmem), magicmem); 352 | } 353 | 354 | reg_t fds_t::alloc(int fd) 355 | { 356 | reg_t i; 357 | for (i = 0; i < fds.size(); i++) 358 | if (fds[i] == -1) 359 | break; 360 | 361 | if (i == fds.size()) 362 | fds.resize(i+1); 363 | 364 | fds[i] = fd; 365 | return i; 366 | } 367 | 368 | void fds_t::dealloc(reg_t fd) 369 | { 370 | fds[fd] = -1; 371 | } 372 | 373 | int fds_t::lookup(reg_t fd) 374 | { 375 | if (int(fd) == RISCV_AT_FDCWD) 376 | return AT_FDCWD; 377 | return fd >= fds.size() ? -1 : fds[fd]; 378 | } 379 | 380 | void syscall_t::set_chroot(const char* where) 381 | { 382 | char buf1[PATH_MAX], buf2[PATH_MAX]; 383 | 384 | if (getcwd(buf1, sizeof(buf1)) == NULL 385 | || chdir(where) != 0 386 | || getcwd(buf2, sizeof(buf2)) == NULL 387 | || chdir(buf1) != 0) 388 | { 389 | fprintf(stderr, "could not chroot to %s\n", where); 390 | exit(-1); 391 | } 392 | 393 | chroot = buf2; 394 | } 395 | -------------------------------------------------------------------------------- /fesvr/syscall.h: -------------------------------------------------------------------------------- 1 | // See LICENSE for license details. 2 | 3 | #ifndef __SYSCALL_H 4 | #define __SYSCALL_H 5 | 6 | #include "device.h" 7 | #include "memif.h" 8 | #include 9 | #include 10 | 11 | class syscall_t; 12 | typedef reg_t (syscall_t::*syscall_func_t)(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t); 13 | 14 | class htif_t; 15 | class memif_t; 16 | 17 | class fds_t 18 | { 19 | public: 20 | reg_t alloc(int fd); 21 | void dealloc(reg_t fd); 22 | int lookup(reg_t fd); 23 | private: 24 | std::vector fds; 25 | }; 26 | 27 | class syscall_t : public device_t 28 | { 29 | public: 30 | syscall_t(htif_t*); 31 | 32 | void set_chroot(const char* where); 33 | 34 | private: 35 | const char* identity() { return "syscall_proxy"; } 36 | 37 | htif_t* htif; 38 | memif_t* memif; 39 | std::vector table; 40 | fds_t fds; 41 | 42 | void handle_syscall(command_t cmd); 43 | void dispatch(addr_t mm); 44 | 45 | std::string chroot; 46 | std::string do_chroot(const char* fn); 47 | std::string undo_chroot(const char* fn); 48 | 49 | reg_t sys_exit(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t); 50 | reg_t sys_openat(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t); 51 | reg_t sys_read(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t); 52 | reg_t sys_pread(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t); 53 | reg_t sys_write(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t); 54 | reg_t sys_pwrite(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t); 55 | reg_t sys_close(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t); 56 | reg_t sys_lseek(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t); 57 | reg_t sys_fstat(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t); 58 | reg_t sys_lstat(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t); 59 | reg_t sys_fstatat(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t); 60 | reg_t sys_faccessat(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t); 61 | reg_t sys_fcntl(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t); 62 | reg_t sys_ftruncate(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t); 63 | reg_t sys_renameat(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t); 64 | reg_t sys_linkat(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t); 65 | reg_t sys_unlinkat(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t); 66 | reg_t sys_mkdirat(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t); 67 | reg_t sys_getcwd(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t); 68 | reg_t sys_getmainvars(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t); 69 | reg_t sys_chdir(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t); 70 | }; 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /fesvr/term.cc: -------------------------------------------------------------------------------- 1 | #include "term.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class canonical_termios_t 9 | { 10 | public: 11 | canonical_termios_t() 12 | : restore_tios(false) 13 | { 14 | if (tcgetattr(0, &old_tios) == 0) 15 | { 16 | struct termios new_tios = old_tios; 17 | new_tios.c_lflag &= ~(ICANON | ECHO); 18 | if (tcsetattr(0, TCSANOW, &new_tios) == 0) 19 | restore_tios = true; 20 | } 21 | } 22 | 23 | ~canonical_termios_t() 24 | { 25 | if (restore_tios) 26 | tcsetattr(0, TCSANOW, &old_tios); 27 | } 28 | private: 29 | struct termios old_tios; 30 | bool restore_tios; 31 | }; 32 | 33 | static canonical_termios_t tios; // exit() will clean up for us 34 | 35 | int canonical_terminal_t::read() 36 | { 37 | struct pollfd pfd; 38 | pfd.fd = 0; 39 | pfd.events = POLLIN; 40 | int ret = poll(&pfd, 1, 0); 41 | if (ret <= 0 || !(pfd.revents & POLLIN)) 42 | return -1; 43 | 44 | unsigned char ch; 45 | ret = ::read(0, &ch, 1); 46 | return ret <= 0 ? -1 : ch; 47 | } 48 | 49 | void canonical_terminal_t::write(char ch) 50 | { 51 | if (::write(1, &ch, 1) != 1) 52 | abort(); 53 | } 54 | -------------------------------------------------------------------------------- /fesvr/term.h: -------------------------------------------------------------------------------- 1 | #ifndef _TERM_H 2 | #define _TERM_H 3 | 4 | class canonical_terminal_t 5 | { 6 | public: 7 | static int read(); 8 | static void write(char); 9 | }; 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /fesvr/tsi.cc: -------------------------------------------------------------------------------- 1 | #include "tsi.h" 2 | #include 3 | #include 4 | 5 | #define NHARTS_MAX 16 6 | 7 | void tsi_t::host_thread(void *arg) 8 | { 9 | tsi_t *tsi = static_cast(arg); 10 | tsi->run(); 11 | 12 | while (true) 13 | tsi->target->switch_to(); 14 | } 15 | 16 | tsi_t::tsi_t(int argc, char** argv) : htif_t(argc, argv) 17 | { 18 | target = context_t::current(); 19 | host.init(host_thread, this); 20 | } 21 | 22 | tsi_t::~tsi_t(void) 23 | { 24 | } 25 | 26 | #define MSIP_BASE 0x2000000 27 | 28 | // Interrupt core 0 to make it start executing the program in DRAM 29 | void tsi_t::reset() 30 | { 31 | uint32_t one = 1; 32 | 33 | write_chunk(MSIP_BASE, sizeof(uint32_t), &one); 34 | } 35 | 36 | void tsi_t::push_addr(addr_t addr) 37 | { 38 | for (int i = 0; i < SAI_ADDR_CHUNKS; i++) { 39 | in_data.push_back(addr & 0xffffffff); 40 | addr = addr >> 32; 41 | } 42 | } 43 | 44 | void tsi_t::push_len(addr_t len) 45 | { 46 | for (int i = 0; i < SAI_LEN_CHUNKS; i++) { 47 | in_data.push_back(len & 0xffffffff); 48 | len = len >> 32; 49 | } 50 | } 51 | 52 | void tsi_t::read_chunk(addr_t taddr, size_t nbytes, void* dst) 53 | { 54 | uint32_t *result = static_cast(dst); 55 | size_t len = nbytes / sizeof(uint32_t); 56 | 57 | in_data.push_back(SAI_CMD_READ); 58 | push_addr(taddr); 59 | push_len(len - 1); 60 | 61 | for (size_t i = 0; i < len; i++) { 62 | while (out_data.empty()) 63 | switch_to_target(); 64 | result[i] = out_data.front(); 65 | out_data.pop_front(); 66 | } 67 | } 68 | 69 | void tsi_t::write_chunk(addr_t taddr, size_t nbytes, const void* src) 70 | { 71 | const uint32_t *src_data = static_cast(src); 72 | size_t len = nbytes / sizeof(uint32_t); 73 | 74 | in_data.push_back(SAI_CMD_WRITE); 75 | push_addr(taddr); 76 | push_len(len - 1); 77 | 78 | in_data.insert(in_data.end(), src_data, src_data + len); 79 | } 80 | 81 | void tsi_t::send_word(uint32_t word) 82 | { 83 | out_data.push_back(word); 84 | } 85 | 86 | uint32_t tsi_t::recv_word(void) 87 | { 88 | uint32_t word = in_data.front(); 89 | in_data.pop_front(); 90 | return word; 91 | } 92 | 93 | bool tsi_t::data_available(void) 94 | { 95 | return !in_data.empty(); 96 | } 97 | 98 | void tsi_t::switch_to_host(void) 99 | { 100 | host.switch_to(); 101 | } 102 | 103 | void tsi_t::switch_to_target(void) 104 | { 105 | target->switch_to(); 106 | } 107 | 108 | void tsi_t::tick(bool out_valid, uint32_t out_bits, bool in_ready) 109 | { 110 | if (out_valid && out_ready()) 111 | out_data.push_back(out_bits); 112 | 113 | if (in_valid() && in_ready) 114 | in_data.pop_front(); 115 | } 116 | -------------------------------------------------------------------------------- /fesvr/tsi.h: -------------------------------------------------------------------------------- 1 | #ifndef __SAI_H 2 | #define __SAI_H 3 | 4 | #include "htif.h" 5 | #include "context.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define SAI_CMD_READ 0 13 | #define SAI_CMD_WRITE 1 14 | 15 | #define SAI_ADDR_CHUNKS 2 16 | #define SAI_LEN_CHUNKS 2 17 | 18 | class tsi_t : public htif_t 19 | { 20 | public: 21 | tsi_t(int argc, char** argv); 22 | virtual ~tsi_t(); 23 | 24 | bool data_available(); 25 | void send_word(uint32_t word); 26 | uint32_t recv_word(); 27 | void switch_to_host(); 28 | 29 | uint32_t in_bits() { return in_data.front(); } 30 | bool in_valid() { return !in_data.empty(); } 31 | bool out_ready() { return true; } 32 | void tick(bool out_valid, uint32_t out_bits, bool in_ready); 33 | 34 | protected: 35 | void reset() override; 36 | void read_chunk(addr_t taddr, size_t nbytes, void* dst) override; 37 | void write_chunk(addr_t taddr, size_t nbytes, const void* src) override; 38 | void switch_to_target(); 39 | 40 | size_t chunk_align() { return 4; } 41 | size_t chunk_max_size() { return 1024; } 42 | 43 | int get_ipi_addrs(addr_t *addrs); 44 | 45 | private: 46 | context_t host; 47 | context_t* target; 48 | std::deque in_data; 49 | std::deque out_data; 50 | 51 | void push_addr(addr_t addr); 52 | void push_len(addr_t len); 53 | 54 | static void host_thread(void *tsi); 55 | }; 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /riscv-fesvr.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@prefix@ 3 | libdir=${prefix}/@libdir@ 4 | includedir=${prefix}/@includedir@ 5 | 6 | Name: riscv-fesvr 7 | Description: RISC-V front-end server 8 | Version: git 9 | Libs: -Wl,-rpath,${libdir} -L${libdir} -lfesvr 10 | Cflags: -I${includedir} 11 | URL: http://riscv.org/download.html#tab_fesvr 12 | -------------------------------------------------------------------------------- /scripts/config.sub: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Configuration validation subroutine script. 3 | # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 4 | # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 5 | # Free Software Foundation, Inc. 6 | 7 | timestamp='2009-09-02' 8 | 9 | # This file is (in principle) common to ALL GNU software. 10 | # The presence of a machine in this file suggests that SOME GNU software 11 | # can handle that machine. It does not imply ALL GNU software can. 12 | # 13 | # This file is free software; you can redistribute it and/or modify 14 | # it under the terms of the GNU General Public License as published by 15 | # the Free Software Foundation; either version 2 of the License, or 16 | # (at your option) any later version. 17 | # 18 | # This program is distributed in the hope that it will be useful, 19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | # GNU General Public License for more details. 22 | # 23 | # You should have received a copy of the GNU General Public License 24 | # along with this program; if not, write to the Free Software 25 | # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 26 | # 02110-1301, USA. 27 | # 28 | # As a special exception to the GNU General Public License, if you 29 | # distribute this file as part of a program that contains a 30 | # configuration script generated by Autoconf, you may include it under 31 | # the same distribution terms that you use for the rest of that program. 32 | 33 | 34 | # Please send patches to . Submit a context 35 | # diff and a properly formatted ChangeLog entry. 36 | # 37 | # Configuration subroutine to validate and canonicalize a configuration type. 38 | # Supply the specified configuration type as an argument. 39 | # If it is invalid, we print an error message on stderr and exit with code 1. 40 | # Otherwise, we print the canonical config type on stdout and succeed. 41 | 42 | # This file is supposed to be the same for all GNU packages 43 | # and recognize all the CPU types, system types and aliases 44 | # that are meaningful with *any* GNU software. 45 | # Each package is responsible for reporting which valid configurations 46 | # it does not support. The user should be able to distinguish 47 | # a failure to support a valid configuration from a meaningless 48 | # configuration. 49 | 50 | # The goal of this file is to map all the various variations of a given 51 | # machine specification into a single specification in the form: 52 | # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM 53 | # or in some cases, the newer four-part form: 54 | # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM 55 | # It is wrong to echo any other type of specification. 56 | 57 | me=`echo "$0" | sed -e 's,.*/,,'` 58 | 59 | usage="\ 60 | Usage: $0 [OPTION] CPU-MFR-OPSYS 61 | $0 [OPTION] ALIAS 62 | 63 | Canonicalize a configuration name. 64 | 65 | Operation modes: 66 | -h, --help print this help, then exit 67 | -t, --time-stamp print date of last modification, then exit 68 | -v, --version print version number, then exit 69 | 70 | Report bugs and patches to ." 71 | 72 | version="\ 73 | GNU config.sub ($timestamp) 74 | 75 | Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 76 | 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. 77 | 78 | This is free software; see the source for copying conditions. There is NO 79 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." 80 | 81 | help=" 82 | Try \`$me --help' for more information." 83 | 84 | # Parse command line 85 | while test $# -gt 0 ; do 86 | case $1 in 87 | --time-stamp | --time* | -t ) 88 | echo "$timestamp" ; exit ;; 89 | --version | -v ) 90 | echo "$version" ; exit ;; 91 | --help | --h* | -h ) 92 | echo "$usage"; exit ;; 93 | -- ) # Stop option processing 94 | shift; break ;; 95 | - ) # Use stdin as input. 96 | break ;; 97 | -* ) 98 | echo "$me: invalid option $1$help" 99 | exit 1 ;; 100 | 101 | *local*) 102 | # First pass through any local machine types. 103 | echo $1 104 | exit ;; 105 | 106 | * ) 107 | break ;; 108 | esac 109 | done 110 | 111 | case $# in 112 | 0) echo "$me: missing argument$help" >&2 113 | exit 1;; 114 | 1) ;; 115 | *) echo "$me: too many arguments$help" >&2 116 | exit 1;; 117 | esac 118 | 119 | # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). 120 | # Here we must recognize all the valid KERNEL-OS combinations. 121 | maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` 122 | case $maybe_os in 123 | nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ 124 | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ 125 | storm-chaos* | os2-emx* | rtmk-nova*) 126 | os=-$maybe_os 127 | basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` 128 | ;; 129 | *) 130 | basic_machine=`echo $1 | sed 's/-[^-]*$//'` 131 | if [ $basic_machine != $1 ] 132 | then os=`echo $1 | sed 's/.*-/-/'` 133 | else os=; fi 134 | ;; 135 | esac 136 | 137 | ### Let's recognize common machines as not being operating systems so 138 | ### that things like config.sub decstation-3100 work. We also 139 | ### recognize some manufacturers as not being operating systems, so we 140 | ### can provide default operating systems below. 141 | case $os in 142 | -sun*os*) 143 | # Prevent following clause from handling this invalid input. 144 | ;; 145 | -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ 146 | -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ 147 | -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ 148 | -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ 149 | -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ 150 | -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ 151 | -apple | -axis | -knuth | -cray) 152 | os= 153 | basic_machine=$1 154 | ;; 155 | -sim | -cisco | -oki | -wec | -winbond) 156 | os= 157 | basic_machine=$1 158 | ;; 159 | -scout) 160 | ;; 161 | -wrs) 162 | os=-vxworks 163 | basic_machine=$1 164 | ;; 165 | -chorusos*) 166 | os=-chorusos 167 | basic_machine=$1 168 | ;; 169 | -chorusrdb) 170 | os=-chorusrdb 171 | basic_machine=$1 172 | ;; 173 | -hiux*) 174 | os=-hiuxwe2 175 | ;; 176 | -sco6) 177 | os=-sco5v6 178 | basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` 179 | ;; 180 | -sco5) 181 | os=-sco3.2v5 182 | basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` 183 | ;; 184 | -sco4) 185 | os=-sco3.2v4 186 | basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` 187 | ;; 188 | -sco3.2.[4-9]*) 189 | os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` 190 | basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` 191 | ;; 192 | -sco3.2v[4-9]*) 193 | # Don't forget version if it is 3.2v4 or newer. 194 | basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` 195 | ;; 196 | -sco5v6*) 197 | # Don't forget version if it is 3.2v4 or newer. 198 | basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` 199 | ;; 200 | -sco*) 201 | os=-sco3.2v2 202 | basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` 203 | ;; 204 | -udk*) 205 | basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` 206 | ;; 207 | -isc) 208 | os=-isc2.2 209 | basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` 210 | ;; 211 | -clix*) 212 | basic_machine=clipper-intergraph 213 | ;; 214 | -isc*) 215 | basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` 216 | ;; 217 | -lynx*) 218 | os=-lynxos 219 | ;; 220 | -ptx*) 221 | basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` 222 | ;; 223 | -windowsnt*) 224 | os=`echo $os | sed -e 's/windowsnt/winnt/'` 225 | ;; 226 | -psos*) 227 | os=-psos 228 | ;; 229 | -mint | -mint[0-9]*) 230 | basic_machine=m68k-atari 231 | os=-mint 232 | ;; 233 | esac 234 | 235 | # Decode aliases for certain CPU-COMPANY combinations. 236 | case $basic_machine in 237 | # Recognize the basic CPU types without company name. 238 | # Some are omitted here because they have special meanings below. 239 | 1750a | 580 \ 240 | | a29k \ 241 | | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ 242 | | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ 243 | | am33_2.0 \ 244 | | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ 245 | | bfin \ 246 | | c4x | clipper \ 247 | | d10v | d30v | dlx | dsp16xx \ 248 | | fido | fr30 | frv \ 249 | | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ 250 | | i370 | i860 | i960 | ia64 \ 251 | | ip2k | iq2000 \ 252 | | m32c | m32r | m32rle | m68000 | m68k | m88k \ 253 | | maxq | mb | microblaze | mcore | mep \ 254 | | mips | mipsbe | mipseb | mipsel | mipsle \ 255 | | mips16 \ 256 | | mips64 | mips64el \ 257 | | mips64vr | mips64vrel \ 258 | | mips64orion | mips64orionel \ 259 | | mips64vr4100 | mips64vr4100el \ 260 | | mips64vr4300 | mips64vr4300el \ 261 | | mips64vr5000 | mips64vr5000el \ 262 | | mips64vr5900 | mips64vr5900el \ 263 | | mipsisa32 | mipsisa32el \ 264 | | mipsisa32r2 | mipsisa32r2el \ 265 | | mipsisa64 | mipsisa64el \ 266 | | mipsisa64r2 | mipsisa64r2el \ 267 | | mipsisa64sb1 | mipsisa64sb1el \ 268 | | mipsisa64sr71k | mipsisa64sr71kel \ 269 | | mipstx39 | mipstx39el \ 270 | | mn10200 | mn10300 \ 271 | | mt \ 272 | | msp430 \ 273 | | nios | nios2 \ 274 | | ns16k | ns32k \ 275 | | or32 \ 276 | | pdp10 | pdp11 | pj | pjl \ 277 | | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ 278 | | pyramid \ 279 | | score \ 280 | | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ 281 | | sh64 | sh64le \ 282 | | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ 283 | | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ 284 | | spu | strongarm \ 285 | | tahoe | thumb | tic4x | tic80 | tron \ 286 | | v850 | v850e \ 287 | | we32k \ 288 | | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ 289 | | z8k) 290 | basic_machine=$basic_machine-unknown 291 | ;; 292 | m6811 | m68hc11 | m6812 | m68hc12) 293 | # Motorola 68HC11/12. 294 | basic_machine=$basic_machine-unknown 295 | os=-none 296 | ;; 297 | m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) 298 | ;; 299 | ms1) 300 | basic_machine=mt-unknown 301 | ;; 302 | 303 | # cbatten - Add maven target 304 | maven) 305 | basic_machine=mipsmavenel-ucb 306 | ;; 307 | 308 | # We use `pc' rather than `unknown' 309 | # because (1) that's what they normally are, and 310 | # (2) the word "unknown" tends to confuse beginning users. 311 | i*86 | x86_64) 312 | basic_machine=$basic_machine-pc 313 | ;; 314 | # Object if more than one company name word. 315 | *-*-*) 316 | echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 317 | exit 1 318 | ;; 319 | # Recognize the basic CPU types with company name. 320 | 580-* \ 321 | | a29k-* \ 322 | | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ 323 | | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ 324 | | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ 325 | | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ 326 | | avr-* | avr32-* \ 327 | | bfin-* | bs2000-* \ 328 | | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ 329 | | clipper-* | craynv-* | cydra-* \ 330 | | d10v-* | d30v-* | dlx-* \ 331 | | elxsi-* \ 332 | | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ 333 | | h8300-* | h8500-* \ 334 | | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ 335 | | i*86-* | i860-* | i960-* | ia64-* \ 336 | | ip2k-* | iq2000-* \ 337 | | m32c-* | m32r-* | m32rle-* \ 338 | | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ 339 | | m88110-* | m88k-* | maxq-* | mcore-* \ 340 | | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ 341 | | mips16-* \ 342 | | mips64-* | mips64el-* \ 343 | | mips64vr-* | mips64vrel-* \ 344 | | mips64orion-* | mips64orionel-* \ 345 | | mips64vr4100-* | mips64vr4100el-* \ 346 | | mips64vr4300-* | mips64vr4300el-* \ 347 | | mips64vr5000-* | mips64vr5000el-* \ 348 | | mips64vr5900-* | mips64vr5900el-* \ 349 | | mipsisa32-* | mipsisa32el-* \ 350 | | mipsisa32r2-* | mipsisa32r2el-* \ 351 | | mipsisa64-* | mipsisa64el-* \ 352 | | mipsisa64r2-* | mipsisa64r2el-* \ 353 | | mipsisa64sb1-* | mipsisa64sb1el-* \ 354 | | mipsisa64sr71k-* | mipsisa64sr71kel-* \ 355 | | mipstx39-* | mipstx39el-* \ 356 | | mmix-* \ 357 | | mt-* \ 358 | | msp430-* \ 359 | | nios-* | nios2-* \ 360 | | none-* | np1-* | ns16k-* | ns32k-* \ 361 | | orion-* \ 362 | | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ 363 | | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ 364 | | pyramid-* \ 365 | | romp-* | rs6000-* \ 366 | | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ 367 | | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ 368 | | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ 369 | | sparclite-* \ 370 | | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ 371 | | tahoe-* | thumb-* \ 372 | | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ 373 | | tron-* \ 374 | | v850-* | v850e-* | vax-* \ 375 | | we32k-* \ 376 | | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ 377 | | xstormy16-* | xtensa*-* \ 378 | | ymp-* \ 379 | | z8k-*) 380 | ;; 381 | # Recognize the basic CPU types without company name, with glob match. 382 | xtensa*) 383 | basic_machine=$basic_machine-unknown 384 | ;; 385 | # Recognize the various machine names and aliases which stand 386 | # for a CPU type and a company and sometimes even an OS. 387 | 386bsd) 388 | basic_machine=i386-unknown 389 | os=-bsd 390 | ;; 391 | 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) 392 | basic_machine=m68000-att 393 | ;; 394 | 3b*) 395 | basic_machine=we32k-att 396 | ;; 397 | a29khif) 398 | basic_machine=a29k-amd 399 | os=-udi 400 | ;; 401 | abacus) 402 | basic_machine=abacus-unknown 403 | ;; 404 | adobe68k) 405 | basic_machine=m68010-adobe 406 | os=-scout 407 | ;; 408 | alliant | fx80) 409 | basic_machine=fx80-alliant 410 | ;; 411 | altos | altos3068) 412 | basic_machine=m68k-altos 413 | ;; 414 | am29k) 415 | basic_machine=a29k-none 416 | os=-bsd 417 | ;; 418 | amd64) 419 | basic_machine=x86_64-pc 420 | ;; 421 | amd64-*) 422 | basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` 423 | ;; 424 | amdahl) 425 | basic_machine=580-amdahl 426 | os=-sysv 427 | ;; 428 | amiga | amiga-*) 429 | basic_machine=m68k-unknown 430 | ;; 431 | amigaos | amigados) 432 | basic_machine=m68k-unknown 433 | os=-amigaos 434 | ;; 435 | amigaunix | amix) 436 | basic_machine=m68k-unknown 437 | os=-sysv4 438 | ;; 439 | apollo68) 440 | basic_machine=m68k-apollo 441 | os=-sysv 442 | ;; 443 | apollo68bsd) 444 | basic_machine=m68k-apollo 445 | os=-bsd 446 | ;; 447 | aux) 448 | basic_machine=m68k-apple 449 | os=-aux 450 | ;; 451 | balance) 452 | basic_machine=ns32k-sequent 453 | os=-dynix 454 | ;; 455 | blackfin) 456 | basic_machine=bfin-unknown 457 | os=-linux 458 | ;; 459 | blackfin-*) 460 | basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` 461 | os=-linux 462 | ;; 463 | c90) 464 | basic_machine=c90-cray 465 | os=-unicos 466 | ;; 467 | convex-c1) 468 | basic_machine=c1-convex 469 | os=-bsd 470 | ;; 471 | convex-c2) 472 | basic_machine=c2-convex 473 | os=-bsd 474 | ;; 475 | convex-c32) 476 | basic_machine=c32-convex 477 | os=-bsd 478 | ;; 479 | convex-c34) 480 | basic_machine=c34-convex 481 | os=-bsd 482 | ;; 483 | convex-c38) 484 | basic_machine=c38-convex 485 | os=-bsd 486 | ;; 487 | cray | j90) 488 | basic_machine=j90-cray 489 | os=-unicos 490 | ;; 491 | craynv) 492 | basic_machine=craynv-cray 493 | os=-unicosmp 494 | ;; 495 | cr16) 496 | basic_machine=cr16-unknown 497 | os=-elf 498 | ;; 499 | crds | unos) 500 | basic_machine=m68k-crds 501 | ;; 502 | crisv32 | crisv32-* | etraxfs*) 503 | basic_machine=crisv32-axis 504 | ;; 505 | cris | cris-* | etrax*) 506 | basic_machine=cris-axis 507 | ;; 508 | crx) 509 | basic_machine=crx-unknown 510 | os=-elf 511 | ;; 512 | da30 | da30-*) 513 | basic_machine=m68k-da30 514 | ;; 515 | decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) 516 | basic_machine=mips-dec 517 | ;; 518 | decsystem10* | dec10*) 519 | basic_machine=pdp10-dec 520 | os=-tops10 521 | ;; 522 | decsystem20* | dec20*) 523 | basic_machine=pdp10-dec 524 | os=-tops20 525 | ;; 526 | delta | 3300 | motorola-3300 | motorola-delta \ 527 | | 3300-motorola | delta-motorola) 528 | basic_machine=m68k-motorola 529 | ;; 530 | delta88) 531 | basic_machine=m88k-motorola 532 | os=-sysv3 533 | ;; 534 | djgpp) 535 | basic_machine=i586-pc 536 | os=-msdosdjgpp 537 | ;; 538 | dpx20 | dpx20-*) 539 | basic_machine=rs6000-bull 540 | os=-bosx 541 | ;; 542 | dpx2* | dpx2*-bull) 543 | basic_machine=m68k-bull 544 | os=-sysv3 545 | ;; 546 | ebmon29k) 547 | basic_machine=a29k-amd 548 | os=-ebmon 549 | ;; 550 | elxsi) 551 | basic_machine=elxsi-elxsi 552 | os=-bsd 553 | ;; 554 | encore | umax | mmax) 555 | basic_machine=ns32k-encore 556 | ;; 557 | es1800 | OSE68k | ose68k | ose | OSE) 558 | basic_machine=m68k-ericsson 559 | os=-ose 560 | ;; 561 | fx2800) 562 | basic_machine=i860-alliant 563 | ;; 564 | genix) 565 | basic_machine=ns32k-ns 566 | ;; 567 | gmicro) 568 | basic_machine=tron-gmicro 569 | os=-sysv 570 | ;; 571 | go32) 572 | basic_machine=i386-pc 573 | os=-go32 574 | ;; 575 | h3050r* | hiux*) 576 | basic_machine=hppa1.1-hitachi 577 | os=-hiuxwe2 578 | ;; 579 | h8300hms) 580 | basic_machine=h8300-hitachi 581 | os=-hms 582 | ;; 583 | h8300xray) 584 | basic_machine=h8300-hitachi 585 | os=-xray 586 | ;; 587 | h8500hms) 588 | basic_machine=h8500-hitachi 589 | os=-hms 590 | ;; 591 | harris) 592 | basic_machine=m88k-harris 593 | os=-sysv3 594 | ;; 595 | hp300-*) 596 | basic_machine=m68k-hp 597 | ;; 598 | hp300bsd) 599 | basic_machine=m68k-hp 600 | os=-bsd 601 | ;; 602 | hp300hpux) 603 | basic_machine=m68k-hp 604 | os=-hpux 605 | ;; 606 | hp3k9[0-9][0-9] | hp9[0-9][0-9]) 607 | basic_machine=hppa1.0-hp 608 | ;; 609 | hp9k2[0-9][0-9] | hp9k31[0-9]) 610 | basic_machine=m68000-hp 611 | ;; 612 | hp9k3[2-9][0-9]) 613 | basic_machine=m68k-hp 614 | ;; 615 | hp9k6[0-9][0-9] | hp6[0-9][0-9]) 616 | basic_machine=hppa1.0-hp 617 | ;; 618 | hp9k7[0-79][0-9] | hp7[0-79][0-9]) 619 | basic_machine=hppa1.1-hp 620 | ;; 621 | hp9k78[0-9] | hp78[0-9]) 622 | # FIXME: really hppa2.0-hp 623 | basic_machine=hppa1.1-hp 624 | ;; 625 | hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) 626 | # FIXME: really hppa2.0-hp 627 | basic_machine=hppa1.1-hp 628 | ;; 629 | hp9k8[0-9][13679] | hp8[0-9][13679]) 630 | basic_machine=hppa1.1-hp 631 | ;; 632 | hp9k8[0-9][0-9] | hp8[0-9][0-9]) 633 | basic_machine=hppa1.0-hp 634 | ;; 635 | hppa-next) 636 | os=-nextstep3 637 | ;; 638 | hppaosf) 639 | basic_machine=hppa1.1-hp 640 | os=-osf 641 | ;; 642 | hppro) 643 | basic_machine=hppa1.1-hp 644 | os=-proelf 645 | ;; 646 | i370-ibm* | ibm*) 647 | basic_machine=i370-ibm 648 | ;; 649 | # I'm not sure what "Sysv32" means. Should this be sysv3.2? 650 | i*86v32) 651 | basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` 652 | os=-sysv32 653 | ;; 654 | i*86v4*) 655 | basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` 656 | os=-sysv4 657 | ;; 658 | i*86v) 659 | basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` 660 | os=-sysv 661 | ;; 662 | i*86sol2) 663 | basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` 664 | os=-solaris2 665 | ;; 666 | i386mach) 667 | basic_machine=i386-mach 668 | os=-mach 669 | ;; 670 | i386-vsta | vsta) 671 | basic_machine=i386-unknown 672 | os=-vsta 673 | ;; 674 | iris | iris4d) 675 | basic_machine=mips-sgi 676 | case $os in 677 | -irix*) 678 | ;; 679 | *) 680 | os=-irix4 681 | ;; 682 | esac 683 | ;; 684 | isi68 | isi) 685 | basic_machine=m68k-isi 686 | os=-sysv 687 | ;; 688 | m68knommu) 689 | basic_machine=m68k-unknown 690 | os=-linux 691 | ;; 692 | m68knommu-*) 693 | basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` 694 | os=-linux 695 | ;; 696 | m88k-omron*) 697 | basic_machine=m88k-omron 698 | ;; 699 | magnum | m3230) 700 | basic_machine=mips-mips 701 | os=-sysv 702 | ;; 703 | merlin) 704 | basic_machine=ns32k-utek 705 | os=-sysv 706 | ;; 707 | mingw32) 708 | basic_machine=i386-pc 709 | os=-mingw32 710 | ;; 711 | mingw32ce) 712 | basic_machine=arm-unknown 713 | os=-mingw32ce 714 | ;; 715 | miniframe) 716 | basic_machine=m68000-convergent 717 | ;; 718 | *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) 719 | basic_machine=m68k-atari 720 | os=-mint 721 | ;; 722 | mips3*-*) 723 | basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` 724 | ;; 725 | mips3*) 726 | basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown 727 | ;; 728 | monitor) 729 | basic_machine=m68k-rom68k 730 | os=-coff 731 | ;; 732 | morphos) 733 | basic_machine=powerpc-unknown 734 | os=-morphos 735 | ;; 736 | msdos) 737 | basic_machine=i386-pc 738 | os=-msdos 739 | ;; 740 | ms1-*) 741 | basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` 742 | ;; 743 | mvs) 744 | basic_machine=i370-ibm 745 | os=-mvs 746 | ;; 747 | ncr3000) 748 | basic_machine=i486-ncr 749 | os=-sysv4 750 | ;; 751 | netbsd386) 752 | basic_machine=i386-unknown 753 | os=-netbsd 754 | ;; 755 | netwinder) 756 | basic_machine=armv4l-rebel 757 | os=-linux 758 | ;; 759 | news | news700 | news800 | news900) 760 | basic_machine=m68k-sony 761 | os=-newsos 762 | ;; 763 | news1000) 764 | basic_machine=m68030-sony 765 | os=-newsos 766 | ;; 767 | news-3600 | risc-news) 768 | basic_machine=mips-sony 769 | os=-newsos 770 | ;; 771 | necv70) 772 | basic_machine=v70-nec 773 | os=-sysv 774 | ;; 775 | next | m*-next ) 776 | basic_machine=m68k-next 777 | case $os in 778 | -nextstep* ) 779 | ;; 780 | -ns2*) 781 | os=-nextstep2 782 | ;; 783 | *) 784 | os=-nextstep3 785 | ;; 786 | esac 787 | ;; 788 | nh3000) 789 | basic_machine=m68k-harris 790 | os=-cxux 791 | ;; 792 | nh[45]000) 793 | basic_machine=m88k-harris 794 | os=-cxux 795 | ;; 796 | nindy960) 797 | basic_machine=i960-intel 798 | os=-nindy 799 | ;; 800 | mon960) 801 | basic_machine=i960-intel 802 | os=-mon960 803 | ;; 804 | nonstopux) 805 | basic_machine=mips-compaq 806 | os=-nonstopux 807 | ;; 808 | np1) 809 | basic_machine=np1-gould 810 | ;; 811 | nsr-tandem) 812 | basic_machine=nsr-tandem 813 | ;; 814 | op50n-* | op60c-*) 815 | basic_machine=hppa1.1-oki 816 | os=-proelf 817 | ;; 818 | openrisc | openrisc-*) 819 | basic_machine=or32-unknown 820 | ;; 821 | os400) 822 | basic_machine=powerpc-ibm 823 | os=-os400 824 | ;; 825 | OSE68000 | ose68000) 826 | basic_machine=m68000-ericsson 827 | os=-ose 828 | ;; 829 | os68k) 830 | basic_machine=m68k-none 831 | os=-os68k 832 | ;; 833 | pa-hitachi) 834 | basic_machine=hppa1.1-hitachi 835 | os=-hiuxwe2 836 | ;; 837 | paragon) 838 | basic_machine=i860-intel 839 | os=-osf 840 | ;; 841 | parisc) 842 | basic_machine=hppa-unknown 843 | os=-linux 844 | ;; 845 | parisc-*) 846 | basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` 847 | os=-linux 848 | ;; 849 | pbd) 850 | basic_machine=sparc-tti 851 | ;; 852 | pbb) 853 | basic_machine=m68k-tti 854 | ;; 855 | pc532 | pc532-*) 856 | basic_machine=ns32k-pc532 857 | ;; 858 | pc98) 859 | basic_machine=i386-pc 860 | ;; 861 | pc98-*) 862 | basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` 863 | ;; 864 | pentium | p5 | k5 | k6 | nexgen | viac3) 865 | basic_machine=i586-pc 866 | ;; 867 | pentiumpro | p6 | 6x86 | athlon | athlon_*) 868 | basic_machine=i686-pc 869 | ;; 870 | pentiumii | pentium2 | pentiumiii | pentium3) 871 | basic_machine=i686-pc 872 | ;; 873 | pentium4) 874 | basic_machine=i786-pc 875 | ;; 876 | pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) 877 | basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` 878 | ;; 879 | pentiumpro-* | p6-* | 6x86-* | athlon-*) 880 | basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` 881 | ;; 882 | pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) 883 | basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` 884 | ;; 885 | pentium4-*) 886 | basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` 887 | ;; 888 | pn) 889 | basic_machine=pn-gould 890 | ;; 891 | power) basic_machine=power-ibm 892 | ;; 893 | ppc) basic_machine=powerpc-unknown 894 | ;; 895 | ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` 896 | ;; 897 | ppcle | powerpclittle | ppc-le | powerpc-little) 898 | basic_machine=powerpcle-unknown 899 | ;; 900 | ppcle-* | powerpclittle-*) 901 | basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` 902 | ;; 903 | ppc64) basic_machine=powerpc64-unknown 904 | ;; 905 | ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` 906 | ;; 907 | ppc64le | powerpc64little | ppc64-le | powerpc64-little) 908 | basic_machine=powerpc64le-unknown 909 | ;; 910 | ppc64le-* | powerpc64little-*) 911 | basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` 912 | ;; 913 | ps2) 914 | basic_machine=i386-ibm 915 | ;; 916 | pw32) 917 | basic_machine=i586-unknown 918 | os=-pw32 919 | ;; 920 | rdos) 921 | basic_machine=i386-pc 922 | os=-rdos 923 | ;; 924 | rom68k) 925 | basic_machine=m68k-rom68k 926 | os=-coff 927 | ;; 928 | rm[46]00) 929 | basic_machine=mips-siemens 930 | ;; 931 | rtpc | rtpc-*) 932 | basic_machine=romp-ibm 933 | ;; 934 | s390 | s390-*) 935 | basic_machine=s390-ibm 936 | ;; 937 | s390x | s390x-*) 938 | basic_machine=s390x-ibm 939 | ;; 940 | sa29200) 941 | basic_machine=a29k-amd 942 | os=-udi 943 | ;; 944 | sb1) 945 | basic_machine=mipsisa64sb1-unknown 946 | ;; 947 | sb1el) 948 | basic_machine=mipsisa64sb1el-unknown 949 | ;; 950 | sde) 951 | basic_machine=mipsisa32-sde 952 | os=-elf 953 | ;; 954 | sei) 955 | basic_machine=mips-sei 956 | os=-seiux 957 | ;; 958 | sequent) 959 | basic_machine=i386-sequent 960 | ;; 961 | sh) 962 | basic_machine=sh-hitachi 963 | os=-hms 964 | ;; 965 | sh5el) 966 | basic_machine=sh5le-unknown 967 | ;; 968 | sh64) 969 | basic_machine=sh64-unknown 970 | ;; 971 | sparclite-wrs | simso-wrs) 972 | basic_machine=sparclite-wrs 973 | os=-vxworks 974 | ;; 975 | sps7) 976 | basic_machine=m68k-bull 977 | os=-sysv2 978 | ;; 979 | spur) 980 | basic_machine=spur-unknown 981 | ;; 982 | st2000) 983 | basic_machine=m68k-tandem 984 | ;; 985 | stratus) 986 | basic_machine=i860-stratus 987 | os=-sysv4 988 | ;; 989 | sun2) 990 | basic_machine=m68000-sun 991 | ;; 992 | sun2os3) 993 | basic_machine=m68000-sun 994 | os=-sunos3 995 | ;; 996 | sun2os4) 997 | basic_machine=m68000-sun 998 | os=-sunos4 999 | ;; 1000 | sun3os3) 1001 | basic_machine=m68k-sun 1002 | os=-sunos3 1003 | ;; 1004 | sun3os4) 1005 | basic_machine=m68k-sun 1006 | os=-sunos4 1007 | ;; 1008 | sun4os3) 1009 | basic_machine=sparc-sun 1010 | os=-sunos3 1011 | ;; 1012 | sun4os4) 1013 | basic_machine=sparc-sun 1014 | os=-sunos4 1015 | ;; 1016 | sun4sol2) 1017 | basic_machine=sparc-sun 1018 | os=-solaris2 1019 | ;; 1020 | sun3 | sun3-*) 1021 | basic_machine=m68k-sun 1022 | ;; 1023 | sun4) 1024 | basic_machine=sparc-sun 1025 | ;; 1026 | sun386 | sun386i | roadrunner) 1027 | basic_machine=i386-sun 1028 | ;; 1029 | sv1) 1030 | basic_machine=sv1-cray 1031 | os=-unicos 1032 | ;; 1033 | symmetry) 1034 | basic_machine=i386-sequent 1035 | os=-dynix 1036 | ;; 1037 | t3e) 1038 | basic_machine=alphaev5-cray 1039 | os=-unicos 1040 | ;; 1041 | t90) 1042 | basic_machine=t90-cray 1043 | os=-unicos 1044 | ;; 1045 | tic54x | c54x*) 1046 | basic_machine=tic54x-unknown 1047 | os=-coff 1048 | ;; 1049 | tic55x | c55x*) 1050 | basic_machine=tic55x-unknown 1051 | os=-coff 1052 | ;; 1053 | tic6x | c6x*) 1054 | basic_machine=tic6x-unknown 1055 | os=-coff 1056 | ;; 1057 | tile*) 1058 | basic_machine=tile-unknown 1059 | os=-linux-gnu 1060 | ;; 1061 | tx39) 1062 | basic_machine=mipstx39-unknown 1063 | ;; 1064 | tx39el) 1065 | basic_machine=mipstx39el-unknown 1066 | ;; 1067 | toad1) 1068 | basic_machine=pdp10-xkl 1069 | os=-tops20 1070 | ;; 1071 | tower | tower-32) 1072 | basic_machine=m68k-ncr 1073 | ;; 1074 | tpf) 1075 | basic_machine=s390x-ibm 1076 | os=-tpf 1077 | ;; 1078 | udi29k) 1079 | basic_machine=a29k-amd 1080 | os=-udi 1081 | ;; 1082 | ultra3) 1083 | basic_machine=a29k-nyu 1084 | os=-sym1 1085 | ;; 1086 | v810 | necv810) 1087 | basic_machine=v810-nec 1088 | os=-none 1089 | ;; 1090 | vaxv) 1091 | basic_machine=vax-dec 1092 | os=-sysv 1093 | ;; 1094 | vms) 1095 | basic_machine=vax-dec 1096 | os=-vms 1097 | ;; 1098 | vpp*|vx|vx-*) 1099 | basic_machine=f301-fujitsu 1100 | ;; 1101 | vxworks960) 1102 | basic_machine=i960-wrs 1103 | os=-vxworks 1104 | ;; 1105 | vxworks68) 1106 | basic_machine=m68k-wrs 1107 | os=-vxworks 1108 | ;; 1109 | vxworks29k) 1110 | basic_machine=a29k-wrs 1111 | os=-vxworks 1112 | ;; 1113 | w65*) 1114 | basic_machine=w65-wdc 1115 | os=-none 1116 | ;; 1117 | w89k-*) 1118 | basic_machine=hppa1.1-winbond 1119 | os=-proelf 1120 | ;; 1121 | xbox) 1122 | basic_machine=i686-pc 1123 | os=-mingw32 1124 | ;; 1125 | xps | xps100) 1126 | basic_machine=xps100-honeywell 1127 | ;; 1128 | ymp) 1129 | basic_machine=ymp-cray 1130 | os=-unicos 1131 | ;; 1132 | z8k-*-coff) 1133 | basic_machine=z8k-unknown 1134 | os=-sim 1135 | ;; 1136 | none) 1137 | basic_machine=none-none 1138 | os=-none 1139 | ;; 1140 | 1141 | # Here we handle the default manufacturer of certain CPU types. It is in 1142 | # some cases the only manufacturer, in others, it is the most popular. 1143 | w89k) 1144 | basic_machine=hppa1.1-winbond 1145 | ;; 1146 | op50n) 1147 | basic_machine=hppa1.1-oki 1148 | ;; 1149 | op60c) 1150 | basic_machine=hppa1.1-oki 1151 | ;; 1152 | romp) 1153 | basic_machine=romp-ibm 1154 | ;; 1155 | mmix) 1156 | basic_machine=mmix-knuth 1157 | ;; 1158 | rs6000) 1159 | basic_machine=rs6000-ibm 1160 | ;; 1161 | vax) 1162 | basic_machine=vax-dec 1163 | ;; 1164 | pdp10) 1165 | # there are many clones, so DEC is not a safe bet 1166 | basic_machine=pdp10-unknown 1167 | ;; 1168 | pdp11) 1169 | basic_machine=pdp11-dec 1170 | ;; 1171 | we32k) 1172 | basic_machine=we32k-att 1173 | ;; 1174 | sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele) 1175 | basic_machine=sh-unknown 1176 | ;; 1177 | sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) 1178 | basic_machine=sparc-sun 1179 | ;; 1180 | cydra) 1181 | basic_machine=cydra-cydrome 1182 | ;; 1183 | orion) 1184 | basic_machine=orion-highlevel 1185 | ;; 1186 | orion105) 1187 | basic_machine=clipper-highlevel 1188 | ;; 1189 | mac | mpw | mac-mpw) 1190 | basic_machine=m68k-apple 1191 | ;; 1192 | pmac | pmac-mpw) 1193 | basic_machine=powerpc-apple 1194 | ;; 1195 | *-unknown) 1196 | # Make sure to match an already-canonicalized machine name. 1197 | ;; 1198 | *) 1199 | echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 1200 | exit 1 1201 | ;; 1202 | esac 1203 | 1204 | # Here we canonicalize certain aliases for manufacturers. 1205 | case $basic_machine in 1206 | *-digital*) 1207 | basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` 1208 | ;; 1209 | *-commodore*) 1210 | basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` 1211 | ;; 1212 | *) 1213 | ;; 1214 | esac 1215 | 1216 | # Decode manufacturer-specific aliases for certain operating systems. 1217 | 1218 | if [ x"$os" != x"" ] 1219 | then 1220 | case $os in 1221 | # First match some system type aliases 1222 | # that might get confused with valid system types. 1223 | # -solaris* is a basic system type, with this one exception. 1224 | -solaris1 | -solaris1.*) 1225 | os=`echo $os | sed -e 's|solaris1|sunos4|'` 1226 | ;; 1227 | -solaris) 1228 | os=-solaris2 1229 | ;; 1230 | -svr4*) 1231 | os=-sysv4 1232 | ;; 1233 | -unixware*) 1234 | os=-sysv4.2uw 1235 | ;; 1236 | -gnu/linux*) 1237 | os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` 1238 | ;; 1239 | # First accept the basic system types. 1240 | # The portable systems comes first. 1241 | # Each alternative MUST END IN A *, to match a version number. 1242 | # -sysv* is not here because it comes later, after sysvr4. 1243 | -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ 1244 | | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ 1245 | | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ 1246 | | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ 1247 | | -aos* \ 1248 | | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ 1249 | | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ 1250 | | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ 1251 | | -openbsd* | -solidbsd* \ 1252 | | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ 1253 | | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ 1254 | | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ 1255 | | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ 1256 | | -chorusos* | -chorusrdb* \ 1257 | | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ 1258 | | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ 1259 | | -uxpv* | -beos* | -mpeix* | -udk* \ 1260 | | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ 1261 | | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ 1262 | | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ 1263 | | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ 1264 | | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ 1265 | | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ 1266 | | -skyos* | -haiku* | -rdos* | -toppers* | -drops*) 1267 | # Remember, each alternative MUST END IN *, to match a version number. 1268 | ;; 1269 | -qnx*) 1270 | case $basic_machine in 1271 | x86-* | i*86-*) 1272 | ;; 1273 | *) 1274 | os=-nto$os 1275 | ;; 1276 | esac 1277 | ;; 1278 | -nto-qnx*) 1279 | ;; 1280 | -nto*) 1281 | os=`echo $os | sed -e 's|nto|nto-qnx|'` 1282 | ;; 1283 | -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ 1284 | | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ 1285 | | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) 1286 | ;; 1287 | -mac*) 1288 | os=`echo $os | sed -e 's|mac|macos|'` 1289 | ;; 1290 | -linux-dietlibc) 1291 | os=-linux-dietlibc 1292 | ;; 1293 | -linux*) 1294 | os=`echo $os | sed -e 's|linux|linux-gnu|'` 1295 | ;; 1296 | -sunos5*) 1297 | os=`echo $os | sed -e 's|sunos5|solaris2|'` 1298 | ;; 1299 | -sunos6*) 1300 | os=`echo $os | sed -e 's|sunos6|solaris3|'` 1301 | ;; 1302 | -opened*) 1303 | os=-openedition 1304 | ;; 1305 | -os400*) 1306 | os=-os400 1307 | ;; 1308 | -wince*) 1309 | os=-wince 1310 | ;; 1311 | -osfrose*) 1312 | os=-osfrose 1313 | ;; 1314 | -osf*) 1315 | os=-osf 1316 | ;; 1317 | -utek*) 1318 | os=-bsd 1319 | ;; 1320 | -dynix*) 1321 | os=-bsd 1322 | ;; 1323 | -acis*) 1324 | os=-aos 1325 | ;; 1326 | -atheos*) 1327 | os=-atheos 1328 | ;; 1329 | -syllable*) 1330 | os=-syllable 1331 | ;; 1332 | -386bsd) 1333 | os=-bsd 1334 | ;; 1335 | -ctix* | -uts*) 1336 | os=-sysv 1337 | ;; 1338 | -nova*) 1339 | os=-rtmk-nova 1340 | ;; 1341 | -ns2 ) 1342 | os=-nextstep2 1343 | ;; 1344 | -nsk*) 1345 | os=-nsk 1346 | ;; 1347 | # Preserve the version number of sinix5. 1348 | -sinix5.*) 1349 | os=`echo $os | sed -e 's|sinix|sysv|'` 1350 | ;; 1351 | -sinix*) 1352 | os=-sysv4 1353 | ;; 1354 | -tpf*) 1355 | os=-tpf 1356 | ;; 1357 | -triton*) 1358 | os=-sysv3 1359 | ;; 1360 | -oss*) 1361 | os=-sysv3 1362 | ;; 1363 | -svr4) 1364 | os=-sysv4 1365 | ;; 1366 | -svr3) 1367 | os=-sysv3 1368 | ;; 1369 | -sysvr4) 1370 | os=-sysv4 1371 | ;; 1372 | # This must come after -sysvr4. 1373 | -sysv*) 1374 | ;; 1375 | -ose*) 1376 | os=-ose 1377 | ;; 1378 | -es1800*) 1379 | os=-ose 1380 | ;; 1381 | -xenix) 1382 | os=-xenix 1383 | ;; 1384 | -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) 1385 | os=-mint 1386 | ;; 1387 | -aros*) 1388 | os=-aros 1389 | ;; 1390 | -kaos*) 1391 | os=-kaos 1392 | ;; 1393 | -zvmoe) 1394 | os=-zvmoe 1395 | ;; 1396 | -none) 1397 | ;; 1398 | *) 1399 | # Get rid of the `-' at the beginning of $os. 1400 | os=`echo $os | sed 's/[^-]*-//'` 1401 | echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 1402 | exit 1 1403 | ;; 1404 | esac 1405 | else 1406 | 1407 | # Here we handle the default operating systems that come with various machines. 1408 | # The value should be what the vendor currently ships out the door with their 1409 | # machine or put another way, the most popular os provided with the machine. 1410 | 1411 | # Note that if you're going to try to match "-MANUFACTURER" here (say, 1412 | # "-sun"), then you have to tell the case statement up towards the top 1413 | # that MANUFACTURER isn't an operating system. Otherwise, code above 1414 | # will signal an error saying that MANUFACTURER isn't an operating 1415 | # system, and we'll never get to this point. 1416 | 1417 | case $basic_machine in 1418 | score-*) 1419 | os=-elf 1420 | ;; 1421 | spu-*) 1422 | os=-elf 1423 | ;; 1424 | *-acorn) 1425 | os=-riscix1.2 1426 | ;; 1427 | arm*-rebel) 1428 | os=-linux 1429 | ;; 1430 | arm*-semi) 1431 | os=-aout 1432 | ;; 1433 | c4x-* | tic4x-*) 1434 | os=-coff 1435 | ;; 1436 | # This must come before the *-dec entry. 1437 | pdp10-*) 1438 | os=-tops20 1439 | ;; 1440 | pdp11-*) 1441 | os=-none 1442 | ;; 1443 | *-dec | vax-*) 1444 | os=-ultrix4.2 1445 | ;; 1446 | m68*-apollo) 1447 | os=-domain 1448 | ;; 1449 | i386-sun) 1450 | os=-sunos4.0.2 1451 | ;; 1452 | m68000-sun) 1453 | os=-sunos3 1454 | # This also exists in the configure program, but was not the 1455 | # default. 1456 | # os=-sunos4 1457 | ;; 1458 | m68*-cisco) 1459 | os=-aout 1460 | ;; 1461 | mep-*) 1462 | os=-elf 1463 | ;; 1464 | mips*-cisco) 1465 | os=-elf 1466 | ;; 1467 | mips*-*) 1468 | os=-elf 1469 | ;; 1470 | or32-*) 1471 | os=-coff 1472 | ;; 1473 | *-tti) # must be before sparc entry or we get the wrong os. 1474 | os=-sysv3 1475 | ;; 1476 | sparc-* | *-sun) 1477 | os=-sunos4.1.1 1478 | ;; 1479 | *-be) 1480 | os=-beos 1481 | ;; 1482 | *-haiku) 1483 | os=-haiku 1484 | ;; 1485 | *-ibm) 1486 | os=-aix 1487 | ;; 1488 | *-knuth) 1489 | os=-mmixware 1490 | ;; 1491 | *-wec) 1492 | os=-proelf 1493 | ;; 1494 | *-winbond) 1495 | os=-proelf 1496 | ;; 1497 | *-oki) 1498 | os=-proelf 1499 | ;; 1500 | *-hp) 1501 | os=-hpux 1502 | ;; 1503 | *-hitachi) 1504 | os=-hiux 1505 | ;; 1506 | i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) 1507 | os=-sysv 1508 | ;; 1509 | *-cbm) 1510 | os=-amigaos 1511 | ;; 1512 | *-dg) 1513 | os=-dgux 1514 | ;; 1515 | *-dolphin) 1516 | os=-sysv3 1517 | ;; 1518 | m68k-ccur) 1519 | os=-rtu 1520 | ;; 1521 | m88k-omron*) 1522 | os=-luna 1523 | ;; 1524 | *-next ) 1525 | os=-nextstep 1526 | ;; 1527 | *-sequent) 1528 | os=-ptx 1529 | ;; 1530 | *-crds) 1531 | os=-unos 1532 | ;; 1533 | *-ns) 1534 | os=-genix 1535 | ;; 1536 | i370-*) 1537 | os=-mvs 1538 | ;; 1539 | *-next) 1540 | os=-nextstep3 1541 | ;; 1542 | *-gould) 1543 | os=-sysv 1544 | ;; 1545 | *-highlevel) 1546 | os=-bsd 1547 | ;; 1548 | *-encore) 1549 | os=-bsd 1550 | ;; 1551 | *-sgi) 1552 | os=-irix 1553 | ;; 1554 | *-siemens) 1555 | os=-sysv4 1556 | ;; 1557 | *-masscomp) 1558 | os=-rtu 1559 | ;; 1560 | f30[01]-fujitsu | f700-fujitsu) 1561 | os=-uxpv 1562 | ;; 1563 | *-rom68k) 1564 | os=-coff 1565 | ;; 1566 | *-*bug) 1567 | os=-coff 1568 | ;; 1569 | *-apple) 1570 | os=-macos 1571 | ;; 1572 | *-atari*) 1573 | os=-mint 1574 | ;; 1575 | *) 1576 | os=-none 1577 | ;; 1578 | esac 1579 | fi 1580 | 1581 | # Here we handle the case where we know the os, and the CPU type, but not the 1582 | # manufacturer. We pick the logical manufacturer. 1583 | vendor=unknown 1584 | case $basic_machine in 1585 | *-unknown) 1586 | case $os in 1587 | -riscix*) 1588 | vendor=acorn 1589 | ;; 1590 | -sunos*) 1591 | vendor=sun 1592 | ;; 1593 | -aix*) 1594 | vendor=ibm 1595 | ;; 1596 | -beos*) 1597 | vendor=be 1598 | ;; 1599 | -hpux*) 1600 | vendor=hp 1601 | ;; 1602 | -mpeix*) 1603 | vendor=hp 1604 | ;; 1605 | -hiux*) 1606 | vendor=hitachi 1607 | ;; 1608 | -unos*) 1609 | vendor=crds 1610 | ;; 1611 | -dgux*) 1612 | vendor=dg 1613 | ;; 1614 | -luna*) 1615 | vendor=omron 1616 | ;; 1617 | -genix*) 1618 | vendor=ns 1619 | ;; 1620 | -mvs* | -opened*) 1621 | vendor=ibm 1622 | ;; 1623 | -os400*) 1624 | vendor=ibm 1625 | ;; 1626 | -ptx*) 1627 | vendor=sequent 1628 | ;; 1629 | -tpf*) 1630 | vendor=ibm 1631 | ;; 1632 | -vxsim* | -vxworks* | -windiss*) 1633 | vendor=wrs 1634 | ;; 1635 | -aux*) 1636 | vendor=apple 1637 | ;; 1638 | -hms*) 1639 | vendor=hitachi 1640 | ;; 1641 | -mpw* | -macos*) 1642 | vendor=apple 1643 | ;; 1644 | -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) 1645 | vendor=atari 1646 | ;; 1647 | -vos*) 1648 | vendor=stratus 1649 | ;; 1650 | esac 1651 | basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` 1652 | ;; 1653 | esac 1654 | 1655 | echo $basic_machine$os 1656 | exit 1657 | 1658 | # Local variables: 1659 | # eval: (add-hook 'write-file-hooks 'time-stamp) 1660 | # time-stamp-start: "timestamp='" 1661 | # time-stamp-format: "%:y-%02m-%02d" 1662 | # time-stamp-end: "'" 1663 | # End: 1664 | -------------------------------------------------------------------------------- /scripts/install.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # 3 | # install - install a program, script, or datafile 4 | # This comes from X11R5. 5 | # 6 | # Calling this script install-sh is preferred over install.sh, to prevent 7 | # `make' implicit rules from creating a file called install from it 8 | # when there is no Makefile. 9 | # 10 | # This script is compatible with the BSD install script, but was written 11 | # from scratch. 12 | # 13 | 14 | 15 | # set DOITPROG to echo to test this script 16 | 17 | # Don't use :- since 4.3BSD and earlier shells don't like it. 18 | doit="${DOITPROG-}" 19 | 20 | 21 | # put in absolute paths if you don't have them in your path; or use env. vars. 22 | 23 | mvprog="${MVPROG-mv}" 24 | cpprog="${CPPROG-cp}" 25 | chmodprog="${CHMODPROG-chmod}" 26 | chownprog="${CHOWNPROG-chown}" 27 | chgrpprog="${CHGRPPROG-chgrp}" 28 | stripprog="${STRIPPROG-strip}" 29 | rmprog="${RMPROG-rm}" 30 | mkdirprog="${MKDIRPROG-mkdir}" 31 | 32 | tranformbasename="" 33 | transform_arg="" 34 | instcmd="$mvprog" 35 | chmodcmd="$chmodprog 0755" 36 | chowncmd="" 37 | chgrpcmd="" 38 | stripcmd="" 39 | rmcmd="$rmprog -f" 40 | mvcmd="$mvprog" 41 | src="" 42 | dst="" 43 | dir_arg="" 44 | 45 | while [ x"$1" != x ]; do 46 | case $1 in 47 | -c) instcmd="$cpprog" 48 | shift 49 | continue;; 50 | 51 | -d) dir_arg=true 52 | shift 53 | continue;; 54 | 55 | -m) chmodcmd="$chmodprog $2" 56 | shift 57 | shift 58 | continue;; 59 | 60 | -o) chowncmd="$chownprog $2" 61 | shift 62 | shift 63 | continue;; 64 | 65 | -g) chgrpcmd="$chgrpprog $2" 66 | shift 67 | shift 68 | continue;; 69 | 70 | -s) stripcmd="$stripprog" 71 | shift 72 | continue;; 73 | 74 | -t=*) transformarg=`echo $1 | sed 's/-t=//'` 75 | shift 76 | continue;; 77 | 78 | -b=*) transformbasename=`echo $1 | sed 's/-b=//'` 79 | shift 80 | continue;; 81 | 82 | *) if [ x"$src" = x ] 83 | then 84 | src=$1 85 | else 86 | # this colon is to work around a 386BSD /bin/sh bug 87 | : 88 | dst=$1 89 | fi 90 | shift 91 | continue;; 92 | esac 93 | done 94 | 95 | if [ x"$src" = x ] 96 | then 97 | echo "install: no input file specified" 98 | exit 1 99 | else 100 | true 101 | fi 102 | 103 | if [ x"$dir_arg" != x ]; then 104 | dst=$src 105 | src="" 106 | 107 | if [ -d $dst ]; then 108 | instcmd=: 109 | else 110 | instcmd=mkdir 111 | fi 112 | else 113 | 114 | # Waiting for this to be detected by the "$instcmd $src $dsttmp" command 115 | # might cause directories to be created, which would be especially bad 116 | # if $src (and thus $dsttmp) contains '*'. 117 | 118 | if [ -f $src -o -d $src ] 119 | then 120 | true 121 | else 122 | echo "install: $src does not exist" 123 | exit 1 124 | fi 125 | 126 | if [ x"$dst" = x ] 127 | then 128 | echo "install: no destination specified" 129 | exit 1 130 | else 131 | true 132 | fi 133 | 134 | # If destination is a directory, append the input filename; if your system 135 | # does not like double slashes in filenames, you may need to add some logic 136 | 137 | if [ -d $dst ] 138 | then 139 | dst="$dst"/`basename $src` 140 | else 141 | true 142 | fi 143 | fi 144 | 145 | ## this sed command emulates the dirname command 146 | dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` 147 | 148 | # Make sure that the destination directory exists. 149 | # this part is taken from Noah Friedman's mkinstalldirs script 150 | 151 | # Skip lots of stat calls in the usual case. 152 | if [ ! -d "$dstdir" ]; then 153 | defaultIFS=' 154 | ' 155 | IFS="${IFS-${defaultIFS}}" 156 | 157 | oIFS="${IFS}" 158 | # Some sh's can't handle IFS=/ for some reason. 159 | IFS='%' 160 | set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` 161 | IFS="${oIFS}" 162 | 163 | pathcomp='' 164 | 165 | while [ $# -ne 0 ] ; do 166 | pathcomp="${pathcomp}${1}" 167 | shift 168 | 169 | if [ ! -d "${pathcomp}" ] ; 170 | then 171 | $mkdirprog "${pathcomp}" 172 | else 173 | true 174 | fi 175 | 176 | pathcomp="${pathcomp}/" 177 | done 178 | fi 179 | 180 | if [ x"$dir_arg" != x ] 181 | then 182 | $doit $instcmd $dst && 183 | 184 | if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && 185 | if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && 186 | if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && 187 | if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi 188 | else 189 | 190 | # If we're going to rename the final executable, determine the name now. 191 | 192 | if [ x"$transformarg" = x ] 193 | then 194 | dstfile=`basename $dst` 195 | else 196 | dstfile=`basename $dst $transformbasename | 197 | sed $transformarg`$transformbasename 198 | fi 199 | 200 | # don't allow the sed command to completely eliminate the filename 201 | 202 | if [ x"$dstfile" = x ] 203 | then 204 | dstfile=`basename $dst` 205 | else 206 | true 207 | fi 208 | 209 | # Make a temp file name in the proper directory. 210 | 211 | dsttmp=$dstdir/#inst.$$# 212 | 213 | # Move or copy the file name to the temp name 214 | 215 | $doit $instcmd $src $dsttmp && 216 | 217 | trap "rm -f ${dsttmp}" 0 && 218 | 219 | # and set any options; do chmod last to preserve setuid bits 220 | 221 | # If any of these fail, we abort the whole thing. If we want to 222 | # ignore errors from any of these, just make sure not to ignore 223 | # errors from the above "$doit $instcmd $src $dsttmp" command. 224 | 225 | if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && 226 | if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && 227 | if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && 228 | if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && 229 | 230 | # Now rename the file to the real destination. 231 | 232 | $doit $rmcmd -f $dstdir/$dstfile && 233 | $doit $mvcmd $dsttmp $dstdir/$dstfile 234 | 235 | fi && 236 | 237 | 238 | exit 0 239 | -------------------------------------------------------------------------------- /scripts/mk-install-dirs.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # mkinstalldirs --- make directory hierarchy 3 | # Author: Noah Friedman 4 | # Created: 1993-05-16 5 | # Public domain 6 | 7 | # $Id: mkinstalldirs,v 1.1 2003/09/09 22:24:03 mhampton Exp $ 8 | 9 | errstatus=0 10 | 11 | for file 12 | do 13 | set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` 14 | shift 15 | 16 | pathcomp= 17 | for d 18 | do 19 | pathcomp="$pathcomp$d" 20 | case "$pathcomp" in 21 | -* ) pathcomp=./$pathcomp ;; 22 | esac 23 | 24 | if test ! -d "$pathcomp"; then 25 | echo "mkdir $pathcomp" 1>&2 26 | 27 | mkdir "$pathcomp" || lasterr=$? 28 | 29 | if test ! -d "$pathcomp"; then 30 | errstatus=$lasterr 31 | fi 32 | fi 33 | 34 | pathcomp="$pathcomp/" 35 | done 36 | done 37 | 38 | exit $errstatus 39 | 40 | # mkinstalldirs ends here 41 | -------------------------------------------------------------------------------- /scripts/vcs-version.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #========================================================================= 3 | # vcs-version.sh [options] [src-dir] 4 | #========================================================================= 5 | # 6 | # -h Display this message 7 | # -v Verbose mode 8 | # 9 | # This script will create a version string by querying a version control 10 | # system. The string is appropriate for use in installations and 11 | # distributions. Currently this script assumes we are using git as our 12 | # version control system but it would be possible to check and see if we 13 | # are using an alternative version control system and create a version 14 | # string appropriately. 15 | # 16 | # The script uses git describe plus a few other git commands to create a 17 | # version strings in the following format: 18 | # 19 | # X.Y[-Z-gN][-dirty] 20 | # 21 | # where X is the major release, Y is the minor release, Z is the number 22 | # of commits since the X.Y release, N is an eight digit abbreviated SHA 23 | # hash of the most recent commit and the dirty suffix is appended when 24 | # the working directory used to create the installation or distribution 25 | # is not a pristine checkout. Here are some example version strings: 26 | # 27 | # 0.0 : initial import 28 | # 0.0-3-g99ef6933 : 3rd commit since initial import (N=99ef6933) 29 | # 1.0 : release 1.0 30 | # 1.1-12-g3487ab12 : 12th commit since release 1.1 (N=3487ab12) 31 | # 1.1-12-g3487ab12-dirty : 12th commit since release 1.1 (N=3487ab12) 32 | # 33 | # The last example is from a dirty working directory. To find the last 34 | # release, the script looks for the last tag (does not need to be an 35 | # annotated tag, but probably should be) which matches the format rel-*. 36 | # If there is no such tag in the history, then the script uses 0.0 as 37 | # the release number and counts the total number of commits since the 38 | # original import for the commit count. 39 | # 40 | # If the current directory is not within the working directory, then the 41 | # path to the source directory should be supplied on the command line. 42 | # 43 | # Author : Christopher Batten 44 | # Date : August 5, 2009 45 | 46 | set -e 47 | 48 | #------------------------------------------------------------------------- 49 | # Command line parsing 50 | #------------------------------------------------------------------------- 51 | 52 | if ( test "$1" = "-h" ); then 53 | echo "" 54 | sed -n '3p' $0 | sed -e 's/#//' 55 | sed -n '5,/^$/p' $0 | sed -e 's/#//' 56 | exit 1 57 | fi 58 | 59 | # Source directory command line option 60 | 61 | src_dir="." 62 | if ( test -n "$1" ); then 63 | src_dir="$1" 64 | fi 65 | 66 | #------------------------------------------------------------------------- 67 | # Verify source directory 68 | #------------------------------------------------------------------------- 69 | # If the source directory is not a git working directory output a 70 | # question mark. A distribution will not be in a working directory, but 71 | # the build system should be structured such that this script is not 72 | # executed (and instead the version information should probably come 73 | # from configure). If the user does not specify a source directory use 74 | # the current directory. 75 | 76 | if !( git rev-parse --is-inside-work-tree &> /dev/null ); then 77 | echo "?" 78 | exit 1; 79 | fi 80 | 81 | top_dir=`git rev-parse --show-cdup` 82 | cd ./${top_dir} 83 | 84 | #------------------------------------------------------------------------- 85 | # Create the version string 86 | #------------------------------------------------------------------------- 87 | # See if we can do a describe based on a tag and if not use a default 88 | # release number of 0.0 so that we always get canonical version number 89 | 90 | if ( git describe --tags --match "rel-*" &> /dev/null ); then 91 | ver_str=`git describe --tags --match "rel-*" | sed 's/rel-//'` 92 | else 93 | ver_num="0.0" 94 | ver_commits=`git rev-list --all | wc -l | tr -d " "` 95 | ver_sha=`git describe --tags --match "rel-*" --always` 96 | ver_str="${ver_num}-${ver_commits}-g${ver_sha}" 97 | fi 98 | 99 | # Add a dirty suffix if working directory is dirty 100 | 101 | if !( git diff --quiet ); then 102 | ver_str="${ver_str}-dirty" 103 | else 104 | untracked=`git ls-files --directory --exclude-standard --others -t` 105 | if ( test -n "${untracked}" ); then 106 | ver_str="${ver_str}-dirty" 107 | fi 108 | fi 109 | 110 | # Output the final version string 111 | 112 | echo "${ver_str}" 113 | 114 | # Final exit status 115 | 116 | exit 0; 117 | 118 | --------------------------------------------------------------------------------