/* * nextpnr -- Next Generation Place and Route * * Copyright (C) 2019 gatecat * Copyright (C) 2021 Symbiflow Authors * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ #include "xdc.h" #include #include "context.h" #include "log.h" // Include tcl.h late because it messed with #define's and lets them leave the // scope of the header. #include NEXTPNR_NAMESPACE_BEGIN static int obj_set_from_any(Tcl_Interp *interp, Tcl_Obj *objPtr) { return TCL_ERROR; } static void set_tcl_obj_string(Tcl_Obj *objPtr, const std::string &s) { NPNR_ASSERT(objPtr->bytes == nullptr); // Need to have space for the end null byte. objPtr->bytes = Tcl_Alloc(s.size() + 1); // Length is length of string, not including the end null byte. objPtr->length = s.size(); std::copy(s.begin(), s.end(), objPtr->bytes); objPtr->bytes[objPtr->length] = '\0'; } static void port_update_string(Tcl_Obj *objPtr) { const Context *ctx = static_cast(objPtr->internalRep.twoPtrValue.ptr1); PortInfo *port_info = static_cast(objPtr->internalRep.twoPtrValue.ptr2); std::string port_name = port_info->name.str(ctx); set_tcl_obj_string(objPtr, port_name); } static void cell_update_string(Tcl_Obj *objPtr) { const Context *ctx = static_cast(objPtr->internalRep.twoPtrValue.ptr1); CellInfo *cell_info = static_cast(objPtr->internalRep.twoPtrValue.ptr2); std::string cell_name = cell_info->name.str(ctx); set_tcl_obj_string(objPtr, cell_name); } static void obj_dup(Tcl_Obj *srcPtr, Tcl_Obj *dupPtr) { dupPtr->internalRep.twoPtrValue = srcPtr->internalRep.twoPtrValue; } static void obj_free(Tcl_Obj *objPtr) {} static void Tcl_SetStringResult(Tcl_Interp *interp, const std::string &s) { char *copy = Tcl_Alloc(s.size() + 1); std::copy(s.begin(), s.end(), copy); copy[s.size()] = '\0'; Tcl_SetResult(interp, copy, TCL_DYNAMIC); } static Tcl_ObjType port_object = { "port", obj_free, obj_dup, port_update_string, obj_set_from_any, }; static Tcl_ObjType cell_object = { "cell", obj_free, obj_dup, cell_update_string, obj_set_from_any, }; static int get_ports(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { const Context *ctx = static_cast(data); if (objc == 1) { // Return list of all ports. Tcl_SetStringResult(interp, "Unimplemented"); return TCL_ERROR; } else if (objc == 2) { const char *arg0 = Tcl_GetString(objv[1]); IdString port_name = ctx->id(arg0); auto iter = ctx->ports.find(port_name); if (iter == ctx->ports.end()) { Tcl_SetStringResult(interp, "Could not find port " + port_name.str(ctx)); return TCL_ERROR; } Tcl_Obj *result = Tcl_NewObj(); result->typePtr = &port_object; result->internalRep.twoPtrValue.ptr1 = (void *)(ctx); result->internalRep.twoPtrValue.ptr2 = (void *)(&iter->second); result->bytes = nullptr; port_update_string(result); Tcl_SetObjResult(interp, result); return TCL_OK; } else if (objc > 2) { log_warning("get_ports options not implemented!\n"); return TCL_OK; } else { return TCL_ERROR; } } static int get_cells(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { const Context *ctx = static_cast(data); if (objc == 1) { // Return list of all ports. Tcl_SetStringResult(interp, "Unimplemented"); return TCL_ERROR; } else if (objc == 2) { const char *arg0 = Tcl_GetString(objv[1]); IdString cell_name = ctx->id(arg0); auto iter = ctx->cells.find(cell_name); if (iter == ctx->cells.end()) { Tcl_SetStringResult(interp, "Could not find cell " + cell_name.str(ctx)); return TCL_ERROR; } Tcl_Obj *result = Tcl_NewObj(); result->typePtr = &cell_object; result->internalRep.twoPtrValue.ptr1 = (void *)(ctx); result->internalRep.twoPtrValue.ptr2 = (void *)(iter->second.get()); result->bytes = nullptr; cell_update_string(result); Tcl_SetObjResult(interp, result); return TCL_OK; } else if (objc > 2) { log_warning("get_cells options not implemented!\n"); return TCL_OK; } else { return TCL_ERROR; } } static int set_property(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { // set_property if (objc != 4) { Tcl_SetStringResult(interp, "Only simple 'set_property ' is supported"); return TCL_ERROR; } const char *property = Tcl_GetString(objv[1]); const char *value = Tcl_GetString(objv[2]); const Tcl_Obj *object = objv[3]; if (object->typePtr == &port_object) { const Context *ctx = static_cast(object->internalRep.twoPtrValue.ptr1); PortInfo *port_info = static_cast(object->internalRep.twoPtrValue.ptr2); NPNR_ASSERT(port_info->net != nullptr); CellInfo *cell = ctx->port_cells.at(port_info->name); cell->attrs[ctx->id(property)] = Property(value); } else if (object->typePtr == &cell_object) { const Context *ctx = static_cast(object->internalRep.twoPtrValue.ptr1); CellInfo *cell = static_cast(object->internalRep.twoPtrValue.ptr2); cell->attrs[ctx->id(property)] = Property(value); } return TCL_OK; } static int not_implemented(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { // TCL command that is not yet implemented log_warning("%s command is not implemented!\n", Tcl_GetString(objv[0])); return TCL_OK; } TclInterp::TclInterp(Context *ctx) { interp = Tcl_CreateInterp(); NPNR_ASSERT(Tcl_Init(interp) == TCL_OK); Tcl_RegisterObjType(&port_object); Tcl_RegisterObjType(&cell_object); NPNR_ASSERT(Tcl_Eval(interp, "rename unknown _original_unknown") == TCL_OK); NPNR_ASSERT(Tcl_Eval(interp, "proc unknown args {\n" " set result [scan [lindex $args 0] \"%d\" value]\n" " if { $result == 1 && [llength $args] == 1 } {\n" " return \\[$value\\]\n" " } else {\n" " uplevel 1 [list _original_unknown {*}$args]\n" " }\n" "}") == TCL_OK); Tcl_CreateObjCommand(interp, "get_ports", get_ports, ctx, nullptr); Tcl_CreateObjCommand(interp, "get_cells", get_cells, ctx, nullptr); Tcl_CreateObjCommand(interp, "set_property", set_property, ctx, nullptr); // Not implemented TCL commands Tcl_CreateObjCommand(interp, "create_clock", not_implemented, ctx, nullptr); Tcl_CreateObjCommand(interp, "get_clocks", not_implemented, ctx, nullptr); Tcl_CreateObjCommand(interp, "get_iobanks", not_implemented, ctx, nullptr); Tcl_CreateObjCommand(interp, "get_nets", not_implemented, ctx, nullptr); Tcl_CreateObjCommand(interp, "get_pins", not_implemented, ctx, nullptr); Tcl_CreateObjCommand(interp, "set_clock_groups", not_implemented, ctx, nullptr); Tcl_CreateObjCommand(interp, "set_false_path", not_implemented, ctx, nullptr); Tcl_CreateObjCommand(interp, "set_max_delay", not_implemented, ctx, nullptr); } TclInterp::~TclInterp() { Tcl_DeleteInterp(interp); } NEXTPNR_NAMESPACE_END ' href='#n132'>132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488
/*
 * include/asm-i386/processor.h
 *
 * Copyright (C) 1994 Linus Torvalds
 */

#ifndef __ASM_I386_PROCESSOR_H
#define __ASM_I386_PROCESSOR_H

#include <asm/math_emu.h>
#include <asm/segment.h>
#include <asm/page.h>
#include <asm/types.h>
#include <asm/sigcontext.h>
#include <asm/cpufeature.h>
#include <linux/cache.h>
#include <linux/config.h>
#include <linux/threads.h>

/*
 * Default implementation of macro that returns current
 * instruction pointer ("program counter").
 */
#define current_text_addr() ({ void *pc; __asm__("movl $1f,%0\n1:":"=g" (pc)); pc; })

/*
 *  CPU type and hardware bug flags. Kept separately for each CPU.
 *  Members of this structure are referenced in head.S, so think twice
 *  before touching them. [mj]
 */

struct cpuinfo_x86 {
	__u8	x86;		/* CPU family */
	__u8	x86_vendor;	/* CPU vendor */
	__u8	x86_model;
	__u8	x86_mask;
	char	wp_works_ok;	/* It doesn't on 386's */
	char	hlt_works_ok;	/* Problems on some 486Dx4's and old 386's */
	char	hard_math;
	char	rfu;
       	int	cpuid_level;	/* Maximum supported CPUID level, -1=no CPUID */
	__u32	x86_capability[NCAPINTS];
	char	x86_vendor_id[16];
	char	x86_model_id[64];
	int 	x86_cache_size;  /* in KB - valid for CPUS which support this
				    call  */
	int	fdiv_bug;
	int	f00f_bug;
	int	coma_bug;
	unsigned long loops_per_jiffy;
	unsigned long *pgd_quick;
	unsigned long *pmd_quick;
	unsigned long *pte_quick;
	unsigned long pgtable_cache_sz;
} __attribute__((__aligned__(SMP_CACHE_BYTES)));

#define X86_VENDOR_INTEL 0
#define X86_VENDOR_CYRIX 1
#define X86_VENDOR_AMD 2
#define X86_VENDOR_UMC 3
#define X86_VENDOR_NEXGEN 4
#define X86_VENDOR_CENTAUR 5
#define X86_VENDOR_RISE 6
#define X86_VENDOR_TRANSMETA 7
#define X86_VENDOR_NSC 8
#define X86_VENDOR_UNKNOWN 0xff

/*
 * capabilities of CPUs
 */

extern struct cpuinfo_x86 boot_cpu_data;
extern struct tss_struct init_tss[NR_CPUS];

#ifdef CONFIG_SMP
extern struct cpuinfo_x86 cpu_data[];
#define current_cpu_data cpu_data[smp_processor_id()]
#else
#define cpu_data (&boot_cpu_data)
#define current_cpu_data boot_cpu_data
#endif

#define cpu_has_pge	(test_bit(X86_FEATURE_PGE,  boot_cpu_data.x86_capability))
#define cpu_has_pse	(test_bit(X86_FEATURE_PSE,  boot_cpu_data.x86_capability))
#define cpu_has_pae	(test_bit(X86_FEATURE_PAE,  boot_cpu_data.x86_capability))
#define cpu_has_tsc	(test_bit(X86_FEATURE_TSC,  boot_cpu_data.x86_capability))
#define cpu_has_de	(test_bit(X86_FEATURE_DE,   boot_cpu_data.x86_capability))
#define cpu_has_vme	(test_bit(X86_FEATURE_VME,  boot_cpu_data.x86_capability))
#define cpu_has_fxsr	(test_bit(X86_FEATURE_FXSR, boot_cpu_data.x86_capability))
#define cpu_has_xmm	(test_bit(X86_FEATURE_XMM,  boot_cpu_data.x86_capability))
#define cpu_has_fpu	(test_bit(X86_FEATURE_FPU,  boot_cpu_data.x86_capability))
#define cpu_has_apic	(test_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability))

extern char ignore_irq13;

extern void identify_cpu(struct cpuinfo_x86 *);
extern void print_cpu_info(struct cpuinfo_x86 *);

/*
 * EFLAGS bits
 */
#define X86_EFLAGS_CF	0x00000001 /* Carry Flag */
#define X86_EFLAGS_PF	0x00000004 /* Parity Flag */
#define X86_EFLAGS_AF	0x00000010 /* Auxillary carry Flag */
#define X86_EFLAGS_ZF	0x00000040 /* Zero Flag */
#define X86_EFLAGS_SF	0x00000080 /* Sign Flag */
#define X86_EFLAGS_TF	0x00000100 /* Trap Flag */
#define X86_EFLAGS_IF	0x00000200 /* Interrupt Flag */
#define X86_EFLAGS_DF	0x00000400 /* Direction Flag */
#define X86_EFLAGS_OF	0x00000800 /* Overflow Flag */
#define X86_EFLAGS_IOPL	0x00003000 /* IOPL mask */
#define X86_EFLAGS_NT	0x00004000 /* Nested Task */
#define X86_EFLAGS_RF	0x00010000 /* Resume Flag */
#define X86_EFLAGS_VM	0x00020000 /* Virtual Mode */
#define X86_EFLAGS_AC	0x00040000 /* Alignment Check */
#define X86_EFLAGS_VIF	0x00080000 /* Virtual Interrupt Flag */
#define X86_EFLAGS_VIP	0x00100000 /* Virtual Interrupt Pending */
#define X86_EFLAGS_ID	0x00200000 /* CPUID detection flag */

/*
 * Generic CPUID function
 */
static inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
{
	__asm__("cpuid"
		: "=a" (*eax),
		  "=b" (*ebx),
		  "=c" (*ecx),
		  "=d" (*edx)
		: "0" (op));
}

/*
 * CPUID functions returning a single datum
 */
static inline unsigned int cpuid_eax(unsigned int op)
{
	unsigned int eax;

	__asm__("cpuid"
		: "=a" (eax)
		: "0" (op)
		: "bx", "cx", "dx");
	return eax;
}
static inline unsigned int cpuid_ebx(unsigned int op)
{
	unsigned int eax, ebx;

	__asm__("cpuid"
		: "=a" (eax), "=b" (ebx)
		: "0" (op)
		: "cx", "dx" );
	return ebx;
}
static inline unsigned int cpuid_ecx(unsigned int op)
{
	unsigned int eax, ecx;

	__asm__("cpuid"
		: "=a" (eax), "=c" (ecx)
		: "0" (op)
		: "bx", "dx" );
	return ecx;
}
static inline unsigned int cpuid_edx(unsigned int op)
{
	unsigned int eax, edx;

	__asm__("cpuid"
		: "=a" (eax), "=d" (edx)
		: "0" (op)
		: "bx", "cx");
	return edx;
}

/*
 * Intel CPU features in CR4
 */
#define X86_CR4_VME		0x0001	/* enable vm86 extensions */
#define X86_CR4_PVI		0x0002	/* virtual interrupts flag enable */
#define X86_CR4_TSD		0x0004	/* disable time stamp at ipl 3 */
#define X86_CR4_DE		0x0008	/* enable debugging extensions */
#define X86_CR4_PSE		0x0010	/* enable page size extensions */
#define X86_CR4_PAE		0x0020	/* enable physical address extensions */
#define X86_CR4_MCE		0x0040	/* Machine check enable */
#define X86_CR4_PGE		0x0080	/* enable global pages */
#define X86_CR4_PCE		0x0100	/* enable performance counters at ipl 3 */
#define X86_CR4_OSFXSR		0x0200	/* enable fast FPU save and restore */
#define X86_CR4_OSXMMEXCPT	0x0400	/* enable unmasked SSE exceptions */

#define load_cr3(pgdir) \
	asm volatile("movl %0,%%cr3": :"r" (__pa(pgdir)));

extern unsigned long mmu_cr4_features;

#include <asm/hypervisor.h>

static inline void set_in_cr4 (unsigned long mask)
{
    HYPERVISOR_console_write("No set_in_cr4", 13);
}

static inline void clear_in_cr4 (unsigned long mask)
{
    HYPERVISOR_console_write("No clear_in_cr4", 15);
}

/*
 *      Cyrix CPU configuration register indexes
 */
#define CX86_CCR0 0xc0
#define CX86_CCR1 0xc1
#define CX86_CCR2 0xc2
#define CX86_CCR3 0xc3
#define CX86_CCR4 0xe8
#define CX86_CCR5 0xe9
#define CX86_CCR6 0xea
#define CX86_CCR7 0xeb
#define CX86_DIR0 0xfe
#define CX86_DIR1 0xff
#define CX86_ARR_BASE 0xc4
#define CX86_RCR_BASE 0xdc

/*
 *      Cyrix CPU indexed register access macros
 */

#define getCx86(reg) ({ outb((reg), 0x22); inb(0x23); })

#define setCx86(reg, data) do { \
	outb((reg), 0x22); \
	outb((data), 0x23); \
} while (0)

/*
 * Bus types (default is ISA, but people can check others with these..)
 */
#ifdef CONFIG_EISA
extern int EISA_bus;
#else
#define EISA_bus (0)
#endif
extern int MCA_bus;

/* from system description table in BIOS.  Mostly for MCA use, but
others may find it useful. */
extern unsigned int machine_id;
extern unsigned int machine_submodel_id;
extern unsigned int BIOS_revision;
extern unsigned int mca_pentium_flag;

/*
 * User space process size: 3GB (default).
 */
#define TASK_SIZE	(PAGE_OFFSET)

/* This decides where the kernel will search for a free chunk of vm
 * space during mmap's.
 */
#define TASK_UNMAPPED_BASE	(TASK_SIZE / 3)

/*
 * Size of io_bitmap in longwords: 32 is ports 0-0x3ff.
 */
#define IO_BITMAP_SIZE	32
#define IO_BITMAP_OFFSET offsetof(struct tss_struct,io_bitmap)
#define INVALID_IO_BITMAP_OFFSET 0x8000

struct i387_fsave_struct {
	long	cwd;
	long	swd;
	long	twd;
	long	fip;
	long	fcs;
	long	foo;
	long	fos;
	long	st_space[20];	/* 8*10 bytes for each FP-reg = 80 bytes */
	long	status;		/* software status information */
};

struct i387_fxsave_struct {
	unsigned short	cwd;
	unsigned short	swd;
	unsigned short	twd;
	unsigned short	fop;
	long	fip;
	long	fcs;
	long	foo;
	long	fos;
	long	mxcsr;
	long	reserved;
	long	st_space[32];	/* 8*16 bytes for each FP-reg = 128 bytes */
	long	xmm_space[32];	/* 8*16 bytes for each XMM-reg = 128 bytes */
	long	padding[56];
} __attribute__ ((aligned (16)));

struct i387_soft_struct {
	long	cwd;
	long	swd;
	long	twd;
	long	fip;
	long	fcs;
	long	foo;
	long	fos;
	long	st_space[20];	/* 8*10 bytes for each FP-reg = 80 bytes */
	unsigned char	ftop, changed, lookahead, no_update, rm, alimit;
	struct info	*info;
	unsigned long	entry_eip;
};

union i387_union {
	struct i387_fsave_struct	fsave;
	struct i387_fxsave_struct	fxsave;
	struct i387_soft_struct soft;
};

typedef struct {
	unsigned long seg;