Compare commits

..

3 commits

Author SHA1 Message Date
slederer
0f9215ba3e added missing assembly files, extended .gitignore 2024-09-19 01:04:17 +02:00
slederer
e3ff5106cf import Vivado project 2024-09-19 00:44:08 +02:00
slederer
811a2c17d9 add stuff to gitignore, licenses, README 2024-09-19 00:40:00 +02:00
36 changed files with 21526 additions and 3 deletions

15
.gitignore vendored
View file

@ -1,4 +1,7 @@
*.s pcomp/*.s
progs/*.s
tests/*.s
examples/*.s
*.o *.o
*.exe *.exe
*.bin *.bin
@ -10,6 +13,7 @@
*.sasmout *.sasmout
*.lib *.lib
*.img *.img
*.mem
*.lsym *.lsym
*.zip *.zip
go.sum go.sum
@ -17,5 +21,12 @@ sine.pas
graph.pas graph.pas
graph2.pas graph2.pas
chase.pas chase.pas
*.img
!runtime.s !runtime.s
**/tridoracpu.*/
rtl/arty-a7/mig_dram_0/_tmp/*
rtl/arty-a7/mig_dram_0/doc/*
rtl/arty-a7/mig_dram_0/mig_dram_0*
rtl/arty-a7/mig_dram_0/xil_txt.*
rtl/arty-a7/mig_dram_0/*.veo
rtl/arty-a7/mig_dram_0/*.tcl
rtl/arty-a7/mig_dram_0/*.xml

View file

@ -1,3 +1,5 @@
# rtpair.pas
originally from [https://github.com/Postrediori/Pascal-Raytracer](https://github.com/Postrediori/Pascal-Raytracer), no license specified there
# Attributions for included media files # Attributions for included media files
* ara.pict: Tuxyso / Wikimedia Commons / CC-BY-SA-3.0 * ara.pict: Tuxyso / Wikimedia Commons / CC-BY-SA-3.0
https://commons.wikimedia.org/wiki/File:Ara-Zoo-Muenster-2013.jpg https://commons.wikimedia.org/wiki/File:Ara-Zoo-Muenster-2013.jpg

1501
lib/corelib.s Normal file

File diff suppressed because it is too large Load diff

279
lib/coreloader.s Normal file
View file

@ -0,0 +1,279 @@
; Copyright 2021-2024 Sebastian Lederer. See the file LICENSE.md for details
.ORG 4096
CORELOADER:
; initialize program stack and
; return stack pointers
LOADCP 24060
STOREREG FP
LOADCP 24064
STOREREG RP
LOADCP SYSBOOTTICKS
LOADCP GETTICKS
CALL
STOREI
DROP
LOADCP INITSDCARD
CALL
;LOADCP FIND_SYSPART ; no need to call, it never
;CALL ; returns, so just fall through
.EQU PART_START 0
.EQU EXTENT_SIZE 4
.EQU DIR_SIZE 8
.EQU SLOT_NO 12
.EQU SIZE_BYTES 16
.EQU PRG_START_BLK 20
.EQU FIND_FS 24
.EQU PARTENTRY_SIZE 64
.EQU DIRENTRY_SIZE 64
FIND_SYSPART:
FPADJ -FIND_FS
; load block 0
LOADC 0
LOADCP CARDREADBLK
CALL
DUP ; non-zero return code means error
CBRANCH.Z FIND_1
LOADCP PRINTHEXW
CALL
LOADCP NEWLINE
CALL
LOADC 0
JUMP
FIND_1:
DROP ; remove return code
;LOADC 512
;LOADCP CARD_BUF
;LOADCP HEXDUMP
;CALL
; address of the first partition entry
LOADCP CARD_BUF
FIND_L:
DUP ; dup addr for comparison
LOADCP SYSPART_NAME
LOADC SYSNAME_WORDS
LOADCP _CMPWORDS
CALL
CBRANCH.NZ FIND_FOUND
; go to next entry
LOADC PARTENTRY_SIZE
ADD
; check if address is still
; within the data block
DUP
LOADCP CARD_BUF,512
CMP LT
CBRANCH FIND_L
; remove address
DROP
; not found, complain and
; go back to ROM monitor
LOADCP SYSPART_ERR
LOADCP PRINTLINE
CALL
LOADC 0
JUMP
FIND_FOUND:
; address of the part entry is on stack
; check if partition is enabled
DUP ; duplicate address
LOADC 40 ; add PartFlags field offset
ADD
LOADI
LOADC 1
AND ; check bit 0 (PartEnabled)
CBRANCH.Z FIND_L ; if not set, continue loop
; address of part entry is still on stack
DUP
LOADC 44 ; add startBlock field offset
ADD
LOADI ; get start block number
STORE PART_START
; address of part entry is still on stack
DUP
LOADC 52 ; move to extentSize field
ADD
LOADI ; get value
STORE EXTENT_SIZE
; address of part entry is still on stack
LOADC 56 ; move to dirSize field
ADD
LOADI ; get value
STORE DIR_SIZE
LOADC 0
STORE SLOT_NO ; start with dirslot 0
LOAD PART_START ; start with first block of the partition
FIND_FILE:
DUP ; duplicate block number
LOADCP CARDREADBLK ; read that block
CALL
DROP ; ignore error
; scan directory entries for shell file name
LOADCP CARD_BUF
FIND_FILE_L:
DUP
LOADCP SHELL_NAME
LOADC SHELLNAME_WORDS
LOADCP _CMPWORDS ; compare names
CALL
CBRANCH.NZ FIND_F_FOUND ; exit loop if names match
; check if current dirslot no
; is below maximum number of slots
LOAD SLOT_NO
LOAD DIR_SIZE
CMP GE
CBRANCH FIND_F_NOTFOUND ; max slots reached, exit
; add 1 to SLOT_NO
LOAD SLOT_NO
INC 1
STORE SLOT_NO
; address is still on stack
LOADC DIRENTRY_SIZE
ADD ; go to next dir entry
; check if address is still
; below end of data block
DUP
LOADCP CARD_BUF,512
CMP LT
CBRANCH FIND_FILE_L ; if it is below, loop
DROP ; remove dir entry addr
; block no is still on stack
INC 1
BRANCH FIND_FILE ; read next block
FIND_F_NOTFOUND:
LOADCP SHELL_ERR
LOADCP PRINTLINE
CALL
; remove entry addr and block number
DROP
DROP
LOADC 0
JUMP
FIND_F_FOUND:
; found the file name, now check if it has the right flags
; address of dir entry is still on stack
DUP
LOADC 40 ; add flags field offset
ADD
LOADI ; load flags
LOADC 16 ; test for SlotFirst flag
AND
CBRANCH.Z FIND_FILE_L ; if not set, continue loop
;LOADCP FOUND_MSG
;LOADCP PRINTLINE
;CALL
; we got the right file, now calculate start block
; and get file size from dir entry
; address of dir entry is still on stack
; phys start block = part start + slot_no * (extent_size/512)
LOAD EXTENT_SIZE
LOADC 9
LOADCP _SHRM
CALL
LOAD SLOT_NO
LOADCP _MUL
CALL
LOAD PART_START
ADD
;DUP
;LOADCP PRINTHEXW
;CALL
;LOADC ' '
;LOADCP CONOUT
;CALL
STORE PRG_START_BLK
; address of dir entry is still on stack
LOADC 44
ADD ; add sizeBytes field offset
LOADI ; get size in bytes
;DUP
;LOADCP PRINTHEXW
;CALL
;LOADCP NEWLINE
;CALL
STORE SIZE_BYTES
; remove block number
DROP
; set argument count to 0
; in case this gets called
; by a terminating program
LOADCP PARGCOUNT
LOADC 0
STOREI
DROP
LOADC 0 ; device id is always 0
LOAD PRG_START_BLK
LOAD SIZE_BYTES
; release our stack frame
FPADJ FIND_FS
; load program
LOADCP CORELOAD
CALL
LOADC 0
JUMP
.CPOOL
.EQU SYSNAME_WORDS 4
SYSPART_NAME:
.WORD 6, 32
.BYTE "SYSTEM"
SYSPART_ERR:
.BYTE "No ""SYSTEM"" partition.",13,10,10,0
.EQU SHELLNAME_WORDS 5
SHELL_NAME:
.WORD 10,32
.BYTE "shell.prog"
SHELL_ERR:
.BYTE "No shell on ""SYSTEM"" partition.",13,10,10,0
FOUND_MSG:
.BYTE " shell.prog ",0
%include corelib.s

1053
lib/float32.s Normal file

File diff suppressed because it is too large Load diff

805
lib/rommon.s Normal file
View file

@ -0,0 +1,805 @@
.EQU CR 13
.EQU LF 10
.EQU EOT 4
.EQU ACK 6
.EQU NAK 21
.EQU STX 2
.EQU UART_REG 2048
.EQU MON_ADDR 64512
BRANCH 2 ; the very first instruction is not
; executed correctly
LOADCP 65020 ; initialise FP and RP registers
STOREREG FP
LOADCP 65024
STOREREG RP
LOADCP MON_ADDR
LOADCP 4096
STOREI
DROP
CMDLOOP0:
LOADC MESSAGE
LOADC PRINTLINE
CALL
CMDLOOP:
LOADC NEWLINE
CALL
LOADC PROMPT
CALL
CMDLOOP1:
LOADC CONIN
CALL
LOADC TOUPPER
CALL
DUP
LOADC CONOUT
CALL
LOADC 'A'
CMP.S0 EQ
CBRANCH.Z CMD1
LOADC CMD_A
CALL
BRANCH CMDLOOP2
CMD1:
LOADC 'X'
CMP.S0 EQ
CBRANCH.Z CMD2
LOADC CMD_X
CALL
BRANCH CMDLOOP2
CMD2:
LOADC 'D'
CMP.S0 EQ
CBRANCH.Z CMD3
LOADC CMD_D
CALL
BRANCH CMDLOOP2
CMD3:
LOADC 'G'
CMP.S0 EQ
CBRANCH.Z CMD4
LOADC CMD_G
CALL
BRANCH CMDLOOP2
CMD4:
LOADC 'L'
CMP.S0 EQ
CBRANCH.Z CMD5
LOADC CMD_L
CALL
BRANCH CMDLOOP2
CMD5:
LOADC 'B'
CMP.S0 EQ
CBRANCH.Z CMD6
LOADC CMD_B
CALL
BRANCH CMDLOOP2
CMD6:
DROP
BRANCH CMDLOOP0
CMDLOOP2:
DROP
BRANCH CMDLOOP
; ---- Command 'A': set current address
CMD_A:
LOADC 32
LOADC CONOUT
CALL
LOADC READHEX
CALL
CBRANCH.Z CMD_A_INVALID ; 0 if not valid input
LOADCP MON_ADDR
SWAP
STOREI
DROP ; drop STOREI address
RET
CMD_A_INVALID:
DROP
LOADC '.'
LOADC CONOUT
CALL
RET
; ---- Command 'X': examine current address
CMD_X:
FPADJ -8 ; reserve space for 4 bytes of local variables
LOADCP MON_ADDR
LOADI
STORE 0 ; current memory address
LOADC 4 ; print 8 words
STORE 4 ; Loop counter
CMD_X_LOOP:
LOADC 32 ; print a a space
LOADC CONOUT
CALL
LOAD 0 ; load word via current address
LOADI
LOADC PRINTHEXW ; print it
CALL
LOAD 0
INC 4 ; increment current address
STORE 0
LOAD 4
DEC 1
DUP
STORE 4
CBRANCH.NZ CMD_X_LOOP
LOADCP MON_ADDR
LOAD 0
STOREI
DROP
FPADJ 8
RET
; ---- Command 'D': deposit words at current address
CMD_D:
FPADJ -4
LOADC 4 ; max number of words
STORE 0
CMD_D_LOOP:
LOADC 32 ; print a space
LOADC CONOUT
CALL
LOADC READHEX
CALL
DUP
CBRANCH.Z CMD_D_EXIT ; check for invalid input
SWAP ; swap return code and value
LOADCP MON_ADDR
LOADI ; get current address
SWAP ; swap address and value for STOREI
STOREI 4 ; store the value with post-increment of address
LOADCP MON_ADDR
SWAP ; swap destination address and value for STOREI
STOREI ; store the new address
DROP
LOADC 2 ; compare return code (swapped above) to 2
CMP EQ ; check for valid input and return key
CBRANCH CMD_D_EXIT
LOAD 0
DEC 1
DUP
STORE 0
CBRANCH.NZ CMD_D_LOOP
CMD_D_EXIT:
FPADJ 4
RET
CMD_G:
DROP ; remove input char
LOADCP NEWLINE
CALL
LOADCP MON_ADDR
LOADI
JUMP
CMD_L:
LOADCP NEWLINE
CALL
LOADCP RCVBLOCKS
CALL
LOADCP NEWLINE
CALL
RET
PROMPT:
LOADC '['
LOADC CONOUT
CALL
LOADCP MON_ADDR
LOADI
LOADC PRINTHEXW
CALL
LOADC PROMPT2
LOADC PRINTLINE
CALL
RET
NEWLINE:
LOADC CR
LOADC CONOUT
CALL
LOADC LF
LOADC CONOUT
CALL
RET
; print string of byte characters
; takes pointer to string on eval stack
PRINTLINE:
DUP ; duplicate address as arg to printchar
LOADC PRINTCHAR
CALL
CBRANCH.Z PRINTLINE_EXIT ; if char is zero, exit
INC 1 ; increment address
BRANCH PRINTLINE
PRINTLINE_EXIT:
DROP ; remove address from stack
RET
; print a single character
; takes a byte pointer on eval stack
; returns character on eval stack
PRINTCHAR:
LOADI.S1.X2Y ; load word, keep address on stack
BSEL ; select byte of a word via address
DUP ; check for null byte
CBRANCH.Z PRINTCHAR_XT
DUP
LOADC CONOUT
CALL
PRINTCHAR_XT:
RET
; print a 32-bit hexadecimal number
; takes the value on the stack
PRINTHEXW:
BROT
DUP
LOADC PRINTHEXB
CALL
BROT
DUP
LOADC PRINTHEXB
CALL
BROT
DUP
LOADC PRINTHEXB
CALL
BROT
LOADC PRINTHEXB
CALL
RET
PRINTHEXB:
DUP
SHR
SHR
SHR
SHR
LOADC PRINTNIBBLE
CALL
LOADC PRINTNIBBLE
CALL
RET
PRINTNIBBLE:
LOADC 15
AND ; isolate nibble
LOADC 10
CMPU.S0 GE ; nibble >= 10 ?
CBRANCH.NZ PRINTNIBBLE_1 ; then print a-f
LOADC '0' ; else print 0-9
BRANCH PRINTNIBBLE_2
PRINTNIBBLE_1:
LOADC 55 ; 55 + 10 == 'A'
PRINTNIBBLE_2:
ADD
LOADC CONOUT
CALL
RET
; ------ read a 8-digit hexadecimal number from the console
; stores variables on the user stack, so the FP register must be
; inizialized.
; returns two values on the eval stack:
; - return code (topmost)
; 0 - no valid number
; 1 - valid number
; 2 - valid number and enter was pressed
; - result value
READHEX:
FPADJ -8
LOADC 0 ; current value
STORE 0
LOADC 8 ; max number of digits
STORE 4 ; remaining digits counter
READHEX_1:
LOADC CONIN
CALL
LOADC CR ; RETURN pressed?
CMP.S0 EQ
CBRANCH READHEX_RT
DUP
LOADC CONOUT ; echo character
CALL
LOADC CONVHEXDIGIT
CALL
LOADC -1
CMP.S0 EQ ; invalid character?
CBRANCH.NZ READHEX_XT
LOAD 0
SHL 2 ; shift previous nibble
SHL 2
OR ; combine with last digit
STORE 0
LOAD 4
DEC 1
DUP
STORE 4
CBRANCH.NZ READHEX_1
BRANCH READHEX_XT1
READHEX_RT: ; if no digits were entered, set return code
DROP ; drop read character
LOAD 4 ;remaining digits counter
LOADC 8
CMP NE
CBRANCH READHEX_RT2
LOADC 0 ; no valid input
BRANCH READHEX_XT3
READHEX_RT2:
LOADC 2 ; valid input and return pressed
BRANCH READHEX_XT3
READHEX_XT:
DROP
LOAD 4
LOADC 8
CMP EQ ; if no digits were entered
CBRANCH READHEX_XT0
READHEX_XT1:
LOADC 1 ; valid input flag
BRANCH READHEX_XT3
READHEX_XT0:
LOADC 0
READHEX_XT3:
LOAD 0
SWAP
FPADJ 8
RET
; ------ convert character on the eval stack to upper case
TOUPPER:
LOADC 'a'
CMP.S0 LT
CBRANCH TOUPPER_XT
LOADC 'z'
CMP.S0 GT
CBRANCH TOUPPER_XT
LOADC 32
SUB
TOUPPER_XT:
RET
; ------ convert hexadecimal digit to integer
; ------ takes an ascii character as parameter on the eval stack
; ------ returns an integer value from 0-15 on the eval stack,
; ------ or -1 if the character was not a valid hexadecimal digit
CONVHEXDIGIT:
LOADC TOUPPER
CALL
LOADC '0'
CMP.S0 LT ; character < '0'?
CBRANCH.NZ CONVHEXDIGIT_ERR
LOADC '9'
CMP.S0 GT ; character > '9'?
CBRANCH.NZ CONVHEXDIGIT_ISALPHA
LOADC '0' ; character is between '0' and '9', subtract '0'
SUB
BRANCH CONVHEXDIGIT_NBL
CONVHEXDIGIT_ISALPHA:
LOADC 'A'
CMP.S0 LT ; character < 'A'?
CBRANCH.NZ CONVHEXDIGIT_ERR
LOADC 'F'
CMP.S0 GT ; character > 'F'?
CBRANCH.NZ CONVHEXDIGIT_ERR
LOADC 55 ; character is between 'A' and 'F', subtract ('A' - 10)
SUB
CONVHEXDIGIT_NBL:
RET
CONVHEXDIGIT_ERR:
DROP ; remove character from stack
LOADC -1 ; error
RET
; --------- output a character on serial console
; --------- takes a character (padded to a word) on the eval stack
CONOUT:
LOADC UART_REG ; address of UART register
LOADI ; load status
LOADC 256 ; check bit 8 (tx_busy)
AND
CBRANCH.NZ CONOUT ; loop if bit 8 is not zero
; transmitter is idle now, write character
LOADC UART_REG ; address of UART register
SWAP ; swap character and address for STOREI
LOADC 1024 ; TX enable bit
OR ; OR in the character
STOREI
DROP
RET
; ---- wait until a character is received and return it on eval stack
CONIN:
LOADC WAITFORBYTE
CALL
LOADC -1 ; -1 means timeout
CMP.S0 NE
CBRANCH CONIN_XT ; exit if no timeout
DROP ; remove last result
BRANCH CONIN
CONIN_XT:
RET
.EQU L_BLOCKSIZE 32
.EQU L_WORDSIZE 4
.EQU CKSUM_PATTERN $AFFECAFE
RCVBLOCKS:
LOADCP MON_ADDR ; pointer to current write position,
LOADI ; kept on stack
RCVBLOCKS_L:
LOADC WAITFORBYTE ; read header byte
CALL
LOADC -1
CMP.S0 EQ
CBRANCH RCVBLOCKS_XT ; exit on timeout
; check for EOT -> end
LOADC EOT
CMP.S0 EQ
CBRANCH RCVBLOCKS_XT
; check for STX -> read block
LOADC STX
CMP.S0 EQ
CBRANCH RCVBLOCKS_CONT
; anything else -> send NAK
BRANCH RCVBLOCKS_RETRY
RCVBLOCKS_CONT:
DROP ; remove header byte
DUP ; duplicate pointer
LOADC READBLOCK
CALL
LOADC -1
CMP.S0 EQ ; check for timeout
CBRANCH RCVBLOCKS_XT ; exit on timeout
LOADC -2
CMP.S0 EQ ; check for checksum error
CBRANCH RCVBLOCKS_RETRY
DROP ; remove return code
LOADC L_BLOCKSIZE ; advance pointer
ADD
LOADC ACK ; send ACK
LOADC CONOUT
CALL
; next block
BRANCH RCVBLOCKS_L
RCVBLOCKS_RETRY:
DROP ; remove read byte
; send NAK
LOADC NAK
LOADC CONOUT
CALL
; next block
BRANCH RCVBLOCKS_L
RCVBLOCKS_XT:
DROP ; remove pointer
DROP ; remove read byte
RET
; ---- read a sequence of binary words and store into memory
; - arguments: pointer to memory area
READBLOCK:
FPADJ -12
STORE 0 ; buffer pointer
LOADCP L_BLOCKSIZE
STORE 4 ; remaining bytes
LOADC 0
STORE 8 ; checksum
READBLOCK_L:
LOADCP READWORD ; read a word
CALL
LOADC -1 ; check for timeout
CMP EQ
CBRANCH.NZ READBLOCK_ERR
; DUP ; debug
; LOADC PRINTHEXW
; CALL
DUP ; duplicate read word
LOAD 8 ; load checksum
ADD ; checksum = ((checksum + data) ^ pattern) << 1
LOADCP CKSUM_PATTERN
XOR
SHL
STORE 8 ; store new checkcsum
LOAD 0 ; load buffer pointer
SWAP ; swap value and pointer for STOREI
STOREI 4 ; store word and increment pointer
STORE 0 ; store pointer
LOAD 4 ; load remaining bytes
DEC L_WORDSIZE ; decrement by word size
DUP
STORE 4 ; store
CBRANCH.NZ READBLOCK_L ; loop if remaining words not zero
LOADCP READWORD ; read checksum
CALL
LOADC -1 ; check for timeout
CMP EQ
CBRANCH READBLOCK_ERR
LOAD 8 ; load checksum
CMP EQ
CBRANCH READBLOCK_OK
LOADC -2 ; return code for checksum error
BRANCH READBLOCK_XT
READBLOCK_OK:
LOADC 0 ; return 0
READBLOCK_XT:
FPADJ 12
RET
READBLOCK_ERR:
DROP ; remove result
LOAD 4 ; return number of missing bytes
FPADJ 8
RET
; --- read four bytes (msb to lsb) and return as word
; returns: word, error code (-1 for error, 0 otherwise)
READWORD:
LOADCP WAITFORBYTE
CALL
DUP
LOADC -1 ; check for error
CMP EQ
CBRANCH.NZ READWORD_ERR
; first byte is now on stack
BROT ; rotate byte left
LOADCP WAITFORBYTE
CALL
DUP
LOADC -1 ; check for error
CMP EQ
CBRANCH.NZ READWORD_ERR
; second byte is now on stack
OR ; OR last byte with this byte
BROT ; rotate bytes left
LOADCP WAITFORBYTE
CALL
DUP
LOADC -1 ; check for error
CMP EQ
CBRANCH.NZ READWORD_ERR
; third byte is now on stack
OR ; OR last byte with this byte
BROT
LOADCP WAITFORBYTE
CALL
DUP
LOADC -1 ; check for error
CMP EQ
CBRANCH.NZ READWORD_ERR
; fourth byte is now on stack
OR ; OR last byte with this byte
LOADC 0 ; error code (0: no error)
RET
READWORD_ERR:
LOADC -1 ; error code
RET
;---- wait a fixed amount of cycles for a character to be
; received on the UART.
; returns character or -1 on timeout
.EQU MAX_WAIT 20000000
WAITFORBYTE:
LOADCP MAX_WAIT ; maximum wait loops
WAITFORBYTE_L:
LOADC UART_REG ; address of UART register
LOADI ; load status
LOADC 512 ; check bit 9 (rx_avail)
AND
CBRANCH WAITFORBYTE_RX ; if bit 9 is one, a character is available
DEC 1
DUP
CBRANCH.NZ WAITFORBYTE_L
DROP ; remove wait counter from stack
LOADC -1 ; error code
RET
WAITFORBYTE_RX:
DROP ; remove wait counter from stack
LOADC UART_REG
LOADI ; read register again
LOADC 255 ; mask status bits
AND
LOADC UART_REG ; I/O address
LOADC 512 ; set bit 9 (rx_clear)
STOREI ; write register
DROP ; remove address left by STOREI
RET
.CPOOL
;---- boot from SD-card
; declare buffer addresses used by sdcardlib.s
.EQU CSD_BUF 63984
.EQU CARD_BUF 64000
CMD_B:
DROP ; remove input char
LOADCP NEWLINE
CALL
FPADJ -4
; initialize card
LOADC INITSDCARD
CALL
; read partition block
LOADC 0
LOADC CARDREADBLK
CALL
DUP ; non-zero return code means error
CBRANCH.Z CMD_B_1
CMD_B_ERR:
LOADC PRINTHEXW ; print error code
CALL
LOADC NEWLINE
CALL
LOADC 0 ; if we return, we need to
; put a fake input char back on the
; stack because the main loop will
; try to remove it
FPADJ 4
RET
CMD_B_1:
DROP ; remove error code
; check boot partition slot (boot flag)
LOADCP CARD_BUF,104 ; offset partition flags second part slot
LOADI
LOADC 2 ; PartFlags [PartBoot]
CMP EQ
CBRANCH CMD_B_C
; no boot partition
LOADC $B0
BRANCH CMD_B_ERR
CMD_B_C:
; get start block
LOADCP CARD_BUF,108 ; offset startBlock
LOADI
; get block count
LOADCP CARD_BUF,124 ; offset bootBlocks
LOADI
FPADJ -4 ; allocate space for address var
LOADCP MON_ADDR
LOADI
STORE 0 ; initialize dest addr
CMD_B_L:
; read block
OVER ; duplicate block no
LOADC CARDREADBLK
CALL
DUP ; check for error
CBRANCH.Z CMD_B_C2 ; continue if zero (no error)
NIP ; remove start and count, keep error code
NIP
BRANCH CMD_B_ERR
CMD_B_C2: DROP ; remove error code
CMD_B_2:
; copy to destination
LOAD 0 ; dest addr
LOADC COPY_BLK
CALL
; decrement count and loop
LOAD 0 ; increment dest addr
LOADC 512
ADD
STORE 0
SWAP ; swap block no/count, blockno is now ToS
INC 1
SWAP ; count is now ToS
DEC 1
DUP
CBRANCH.NZ CMD_B_L ; if not zero, loop
; jump to coreloader
DROP
DROP
FPADJ 4
LOADCP MON_ADDR
LOADI
JUMP
CMD_B_XT:
FPADJ 4
RET
; copy a sdcard block to destination address
; block size is always 512 byte, source
; is always CARD_BUF
; parameters: dest addr
COPY_BLK:
FPADJ -4
LOADC 128 ; word count
STORE 0
LOADCP CARD_BUF ; src addr
COPY_BLK1:
SWAP
; [ src addr, dest addr ]
OVER ; [ saddr, daddr, saddr ]
LOADI ; [ saddr, daddr, sword ]
STOREI 4 ; [ saddr, daddr + 4 ]
SWAP ; [ daddr + 4, saddr ]
INC 4 ; [ daddr + 4, saddr + 4]
LOAD 0 ; load and decrement counter
DEC 1
DUP
STORE 0 ; store it again
CBRANCH.NZ COPY_BLK1 ; if not zero, loop
DROP ; remove saddr and daddr
DROP
FPADJ 4
RET
.CPOOL
; wait approx. 1 millisecond
;
; 83.333 MHz Clock, three instructions a 4 cycles
; 83333 / 12 = 6944.4166
; works only if executed without wait states (i.e.
; from BRAM/SRAM)
WAIT1MSEC:
LOADCP 6944
WAIT1LOOP:
DEC 1
DUP
CBRANCH.NZ WAIT1LOOP
DROP
RET
%include "sdcardboot.s"
.CPOOL
MESSAGE:
.BYTE 13,10,"ROM Monitor v3.0.3", 13, 10,
"Set A)ddress D)eposit eX)amine L)oad G)o B)oot",13,10,0
PROMPT2:
.BYTE "]> ",0
END:

613
lib/sdcardboot.s Normal file
View file

@ -0,0 +1,613 @@
.EQU SPIREG $880
.EQU SPI_CTRL_WRITE %100000000000000
.EQU SPI_RX_FILTER_EN %010000000000000
.EQU SPI_TXRX_EN %001000000000000
.EQU SPI_CLK_F_EN %000100000000000
.EQU SPI_CLK_DIV_WR %000010000000000
.EQU SPI_RX_RD %000001000000000
.EQU SPI_TX_WR %000000100000000
.EQU SPI_C_D %100000000000000
.EQU SPI_C_CHG %010000000000000
.EQU SPDI_C_BUSY %001000000000000
.EQU SPI_TX_RDY %000100000000000
.EQU SPI_TX_EMPTY %000010000000000
.EQU SPI_RX_AVAIL %000001000000000
.EQU SPI_RX_OVR %000000100000000
.EQU SPI_TXRX_EN_MASK ~SPI_TXRX_EN
_WAIT:
LOADC 10
_WAITL:
LOADC WAIT1MSEC
CALL
DEC 1
DUP
CBRANCH.NZ _WAITL
DROP
RET
INITSDCARD:
LOADC WAIT1MSEC
CALL
LOADC _SPIINIT1
CALL
;LOADC 'I'
;LOADCP CONOUT
;CALL
LOADC _WAITSPITXRDY
CALL
;LOADC 'W'
;LOADCP CONOUT
;CALL
; send RESET CARD command
LOADC $95 ; send cmd0 with arg 0 and checksum $95
LOADC $0
LOADC $0
LOADC SENDCMD_R1
CALL
DROP ; TODO: handle errors
;LOADCP PRINTHEXW ; print status returned by the card
;CALL
;LOADCP NEWLINE
;CALL
;LOADC '9'
;LOADCP CONOUT
;CALL
LOADC _WAITSPITXRDY
CALL
LOADC _WAIT
CALL
;LOADC '1'
;LOADCP CONOUT
;CALL
LOADC $87
LOADC $01AA
LOADC $8
LOADC SENDCMD_R7
CALL
DROP
LOADC _WAITSPITXRDY
CALL
;LOADC '2'
;LOADCP CONOUT
;CALL
;LOADCP _WAIT
;CALL
;LOADC '.'
;LOADCP CONOUT
;CALL
LOADC CARDINITV2
CALL
;LOADC '+'
;LOADCP CONOUT
;CALL
LOADC CARDFASTCLK
CALL
;LOADC '3'
;LOADCP CONOUT
;CALL
; CMD16: set block size to 512 byte
LOADC 0
LOADC 512
LOADC 16
LOADCP SENDCMD_R1
CALL
DROP
;LOADCP _WAIT
;CALL
;LOADC '4'
;LOADCP CONOUT
;CALL
RET
; read a 512-byte-block from the card
; args: block number
; returns: 0 on success
CARDREADBLK:
LOADC 128 ; number of words in a block
SWAP ; move block number up the stack
LOADCP CARD_BUF
SWAP
LOADC 0
SWAP
LOADC 17 ; CMD17: read block
LOADC SENDCMD_PKT
CALL
RET
; send the card initialization command
; wait until the card responds
CARDINITV2:
LOADC 100 ; try up to 100 times
CARD_LOOP1:
LOADC 50 ; wait 50 msec
CARD_LOOP2:
LOADC WAIT1MSEC
CALL
DEC 1
DUP
CBRANCH.NZ CARD_LOOP2
DROP ; remove loop count value
LOADC $0
LOADC $0
LOADC 58
LOADC SENDCMD_R7 ; send CMD58
CALL
DROP ; ignore result (why?)
LOADC $0
LOADCP $40000000
LOADC 41
LOADC SENDACMD_R1 ; send ACMD41
CALL
CBRANCH.Z CARD_OK ; if result is zero, the command succeded
; and the card initialization is finished
DEC 1
DUP
CBRANCH.NZ CARD_LOOP1
DROP ; remove outer loop count value
RET
CARD_OK:
DROP ; remove outer loop count value
; CMD16: set block size to 512 byte
LOADC 0
LOADC 512
LOADC 16
LOADC SENDCMD_R1
CALL
DROP ; ignore return value
RET
; set fast transfer rate
CARDFASTCLK:
LOADC SPIREG
; set clock divider to ~2,6MHz
LOADC SPI_CLK_DIV_WR+10
STOREI
DROP
RET
; perform first phase of card initialization
; which is to enable clock and wait a bit
; leaves the clock running
_SPIINIT1:
LOADC SPIREG
; set clock divider to ~325KHz
LOADC SPI_CLK_DIV_WR+64
STOREI
DROP
; clear all flags + enable clock
; /CS and MOSI are default high
LOADC SPIREG
LOADCP SPI_CTRL_WRITE,SPI_CLK_F_EN
STOREI
DROP
; we should wait at least for 74 clock cycles now
LOADC 2 ; wait 2 msec, that should be ~300 cycles
_SPIINIT1L:
LOADC WAIT1MSEC
CALL
DEC 1
DUP
CBRANCH.NZ _SPIINIT1L
DROP
LOADC SPIREG
LOADCP SPI_CTRL_WRITE ; disable clock
STOREI
DROP
LOADCP WAIT1MSEC
CALL
RET
; wait for transmission to finish
; (wait for TX_EMPTY bit)
_SPIWAITTX:
LOADC SPIREG
LOADI
LOADCP SPI_TX_EMPTY
AND
CBRANCH.Z _SPIWAITTX
RET
; finalize a command that has been sent:
; wait until the transmitter is idle
; then disable clock and set MOSI high
_SPIENDCMD:
LOADC $FF
LOADC _SENDBYTE
CALL
LOADC $FF
LOADC _SENDBYTE
CALL
;LOADC 'E'
;LOADCP CONOUT
;CALL
LOADC _SPIWAITTX
CALL
;LOADC 'w'
;LOADCP CONOUT
;CALL
LOADC _WAIT_S ; wait a short time
CALL
LOADC SPIREG
LOADCP SPI_IDLE_FLAGS ; turn off transceiver
LOADI
STOREI
DROP
; wait for a few instructions
LOADC 100
SPIEND_LP: DEC 1
DUP
CBRANCH.NZ SPIEND_LP
DROP
RET
_WAIT_S:
LOADC 100
_WAIT_S_L:
DEC 1
DUP
CBRANCH.NZ _WAIT_S_L
DROP
RET
; clear RX fifo
CLEAR_RX_FIFO:
CLEAR_RX_L1:
LOADC SPIREG
LOADI
;DUP
;LOADCP PRINTHEXW
;CALL
;LOADCP NEWLINE
;CALL
LOADC SPI_RX_AVAIL
AND
CBRANCH.Z CLEAR_RX_X
LOADC SPIREG
LOADC SPI_RX_RD
STOREI
DROP
; FIXME: it seems that this
; does not remove a byte from the fifo,
; rx_avail stays on, but only after the first
; byte has been received and read
;LOADC 'x'
;LOADCP CONOUT
;CALL
BRANCH CLEAR_RX_L1
CLEAR_RX_X:
RET
_WAITSPITXRDY:
LOADC SPIREG
LOADI
LOADCP SPI_TX_RDY
AND
CBRANCH.Z _WAITSPITXRDY
RET
; send a command and receive a data packet response
; args: packet size in words, buffer pointer
; checksum byte, 32-bit cmd arg, cmd number
; returns: 0 on success
SENDCMD_PKT:
; first send the command
LOADC SENDCMD_0
CALL
LOADC _RCVBYTE ; receive R1 response
CALL
CBRANCH.NZ SENDCMD_PKT_E ; on success we get 0
; now wait for data token
SENDCMD_PKT_L:
LOADC _RCVBYTE
CALL
LOADC $FF
CMP EQ
CBRANCH SENDCMD_PKT_L
; parameters for _RCVWORDS are on the stack now
LOADC _RCVWORDS
CALL
; receive 2 crc bytes
LOADC _RCVBYTE
CALL
BROT
LOADC _RCVBYTE
CALL
OR
; terminate command
LOADC _SPIENDCMD
CALL
DROP ; we ignore the checksum for now
LOADC 0
RET
SENDCMD_PKT_E:
DROP ; remove remaining args
DROP
LOADC -1 ; return code for error
RET
; send a command and receive a 1-byte-response (R1)
; args: checksum byte, 32-bit cmd arg, cmd number
; returns: received byte
SENDCMD_R1:
LOADC SENDCMD_0
CALL
LOADC _RCVBYTE
CALL
;LOADC 'R'
;LOADCP CONOUT
;CALL
;terminate command (/cs high, disable clock)
LOADC _SPIENDCMD
CALL
RET
; send a command
; args: checksum byte, 32-bit cmd arg, cmd number
SENDCMD_0:
; clear RX FIFO first
LOADC CLEAR_RX_FIFO
CALL
;LOADC '>'
;LOADCP CONOUT
;CALL
; cmd byte is at TOS at this point
LOADC $40 ; or in start of frame bit
OR
LOADC _SENDBYTE
CALL
; cmd arg is at TOS now
LOADC _SENDWORD
CALL
; checksum byte is at TOS now
LOADC _SENDBYTE
CALL
LOADC _XCVR_ENABLE ; enable transceiver last,
CALL ; a complete command should
RET ; fit into the tx fifo
; send ACMD and receive a 1-byte-response (R1)
; args: checksum byte, 32-bit cmd arg, ACMD number
; returns: received byte or -1 if first response byte
; indicated an error
SENDACMD_R1:
LOADC $0
LOADC $0
LOADC 55 ; send CMD55
LOADC SENDCMD_R1
CALL
LOADC 1 ; 1 = idle state, no errors
CMP NE
CBRANCH.NZ SENDACMD_ERR
; pass our args to SENDCMD_R1
LOADC SENDCMD_R1
CALL
RET
SENDACMD_ERR:
LOADCP -1
RET
; send a command and receive a 4+1-byte-response (R7)
; args: checksum byte, 32-bit cmd arg, cmd number
; returns: received word or -1 if first response byte
; indicated an error
SENDCMD_R7:
; send the command
LOADC SENDCMD_0
CALL
;LOADC '7'
;LOADCP CONOUT
;CALL
LOADC _RCVBYTE
CALL
LOADC _RCVWORD
CALL
;terminate command (/cs high, disable clock)
LOADC _SPIENDCMD
CALL
SWAP ; swap 1st response byte with received word
LOADC %011111110 ; check for any error flags
AND
CBRANCH.Z SENDCMD_R7_NOERR
DROP
LOADC -1
SENDCMD_R7_NOERR:
RET
; send a word as 4 bytes, msb first
_SENDWORD:
DUP ; remember original value for later
BROT ; rotate msb to lsb (byte 0)
LOADC 255
AND.S0 ; isolate byte, keep previous value
LOADC _SENDBYTE
CALL
BROT ; byte 1
LOADC 255
AND.S0
LOADC _SENDBYTE
CALL
BROT ; byte 2
LOADC 255
AND
LOADC _SENDBYTE
CALL
; byte 3 is already on the stack
LOADC 255
AND
LOADC _SENDBYTE
CALL
RET
; receive multiple 4-byte-words and store into
; memory buffer
; args: number of words, pointer to buffer
_RCVWORDS:
FPADJ -4
STORE 0 ; store pointer arg into local variable
; keep counter on stack
_RCVWORDS_LP:
LOAD 0 ; load buf pointer for STOREI
LOADC _RCVWORD
CALL ; receive a word
STOREI 4 ; store to buf with postincrement
STORE 0 ; store pointer variable
DEC 1 ; decrement word counter
DUP
CBRANCH.NZ _RCVWORDS_LP ; if not null, loop
DROP ; remove counter value
FPADJ 4
RET
; receive 4 bytes, return as word
_RCVWORD:
LOADC _RCVBYTE ; receive first byte
CALL
BROT ; rotate byte to left
LOADC _RCVBYTE ; receive second byte
CALL
OR ; or first and second byte together
BROT ; rotate 1st + 2nd to left
LOADC _RCVBYTE ; receive third byte
CALL
OR
BROT
LOADCP _RCVBYTE ; receive fourth byte
CALL
OR
RET
_XCVR_ENABLE:
LOADC SPIREG
LOADC SPI_TX_FLAGS
LOADI
STOREI
DROP
RET
; send a byte
; args: byte to be sent
_SENDBYTE:
LOADC SPIREG
LOADI ; load spi io register
LOADCP SPI_TX_RDY
AND ; check tx_rdy bit
CBRANCH.Z _SENDBYTE ; if not set, loop
LOADC SPI_TX_WR ; TX_WR bit
OR ; OR in byte to be send
LOADC SPIREG
SWAP ; swap value and addr for STOREI
STOREI ; store word (flags + data) to io register
DROP ; remove STOREI result
RET
; receive a byte. receiver must be enabled.
; returns: received byte
_RCVBYTE:
LOADC SPIREG
LOADI ; load spi io register
LOADC SPI_RX_AVAIL
AND.S0 ; check rx_avail bit, keep original value
CBRANCH.NZ RECVGOTIT
DROP ; rx_avail not set, remove register value and loop
BRANCH _RCVBYTE
RECVGOTIT:
LOADC SPIREG
LOADC SPI_RX_RD ; remove one byte from rx fifo
STOREI
DROP
LOADC 255
AND ; keep bits 7-0
RET
SPI_TX_FLAGS: .WORD SPI_CTRL_WRITE + SPI_TXRX_EN + SPI_RX_FILTER_EN
SPI_IDLE_FLAGS: .WORD SPI_CTRL_WRITE

795
lib/sdcardlib.s Normal file
View file

@ -0,0 +1,795 @@
; Copyright 2021-2024 Sebastian Lederer. See the file LICENSE.md for details
.EQU SPIREG $880
.EQU SPI_CTRL_WRITE %100000000000000
.EQU SPI_RX_FILTER_EN %010000000000000
.EQU SPI_TXRX_EN %001000000000000
.EQU SPI_CLK_F_EN %000100000000000
.EQU SPI_CLK_DIV_WR %000010000000000
.EQU SPI_RX_RD %000001000000000
.EQU SPI_TX_WR %000000100000000
.EQU SPI_C_D %100000000000000
.EQU SPI_C_CHG %010000000000000
.EQU SPDI_C_BUSY %001000000000000
.EQU SPI_TX_RDY %000100000000000
.EQU SPI_TX_EMPTY %000010000000000
.EQU SPI_RX_AVAIL %000001000000000
.EQU SPI_RX_OVR %000000100000000
.EQU SPI_TXRX_EN_MASK ~SPI_TXRX_EN
_WAIT:
LOADC 10
_WAITL:
LOADCP WAIT1MSEC
CALL
DEC 1
DUP
CBRANCH.NZ _WAITL
DROP
RET
INITSDCARD:
LOADCP WAIT1MSEC
CALL
LOADCP _SPIINIT1
CALL
;LOADC 'I'
;LOADCP CONOUT
;CALL
LOADCP _WAITSPITXRDY
CALL
;LOADC 'W'
;LOADCP CONOUT
;CALL
; send RESET CARD command
LOADC $95 ; send cmd0 with arg 0 and checksum $95
LOADC $0
LOADC $0
LOADCP SENDCMD_R1
CALL
DROP ; TODO: handle errors
;LOADCP PRINTHEXW ; print status returned by the card
;CALL
;LOADCP NEWLINE
;CALL
;LOADC '9'
;LOADCP CONOUT
;CALL
LOADCP _WAITSPITXRDY
CALL
LOADCP _WAIT
CALL
;LOADC '1'
;LOADCP CONOUT
;CALL
LOADC $87
LOADC $01AA
LOADC $8
LOADCP SENDCMD_R7
CALL
DROP
LOADCP _WAITSPITXRDY
CALL
;LOADC '2'
;LOADCP CONOUT
;CALL
;LOADCP _WAIT
;CALL
;LOADC '.'
;LOADCP CONOUT
;CALL
LOADCP CARDINITV2
CALL
;LOADC '+'
;LOADCP CONOUT
;CALL
LOADCP CARDFASTCLK
CALL
;LOADC '3'
;LOADCP CONOUT
;CALL
; CMD16: set block size to 512 byte
LOADC 0
LOADC 512
LOADC 16
LOADCP SENDCMD_R1
CALL
DROP
;LOADCP _WAIT
;CALL
;LOADC '4'
;LOADCP CONOUT
;CALL
RET
; read a 512-byte-block from the card
; args: block number
; returns: 0 on success
CARDREADBLK:
LOADC 128 ; number of words in a block
SWAP ; move block number up the stack
LOADCP CARD_BUF
SWAP
LOADC 0
SWAP
LOADC 17 ; CMD17: read block
LOADCP SENDCMD_PKT
CALL
RET
; determine number of blocks
; returns: number of blocks or -1 on error
CARDSIZE:
LOADC 4
LOADCP CSD_BUF
LOADC 0
LOADC 0
LOADC 9
LOADCP SENDCMD_PKT ; send CMD9
CALL
CBRANCH.NZ CARDSIZE_ERR ; if response is zero, an error occurred
; take bytes 7, 8 and 9 from CSD data
; and add 1 to get card size in ksectors
LOADCP CSD_BUF
INC 4
LOADI
LOADC $3F ; get byte 7 (bits 22-16)
AND
BROT
BROT
LOADCP CSD_BUF ; get bytes 8 and 9 (bits 15-0)
INC 8
LOADI
BROT
BROT
LOADCP $FFFF
AND
OR
INC 1
BROT
SHL 2; multiply by 1024 to get size in sectors
RET
CARDSIZE_ERR:
LOADC -1
RET
; returns 1 if the card was changed, 0 otherwise
CARDCHANGED:
LOADCP SPIREG
LOADI
LOADCP SPI_C_CHG
AND
LOADC 0
CMPU NE
RET
; write a 512-byte-block to the card
; args: block number
; returns: 0 on success
CARDWRITEBLK:
LOADC 128 ; number of words in a block
SWAP ; move block number up the stack
LOADCP CARD_BUF
SWAP
LOADC 0
SWAP
LOADC 24 ; CMD24: write block
LOADCP SENDCMD_TXPKT
CALL
RET
; send the card initialization command
; wait until the card responds
CARDINITV2:
LOADC 100 ; try up to 100 times
CARD_LOOP1:
LOADC 50 ; wait 50 msec
CARD_LOOP2:
LOADCP WAIT1MSEC
CALL
DEC 1
DUP
CBRANCH.NZ CARD_LOOP2
DROP ; remove loop count value
LOADC $0
LOADC $0
LOADC 58
LOADCP SENDCMD_R7 ; send CMD58
CALL
DROP ; ignore result (why?)
LOADC $0
LOADCP $40000000
LOADC 41
LOADCP SENDACMD_R1 ; send ACMD41
CALL
CBRANCH.Z CARD_OK ; if result is zero, the command succeded
; and the card initialization is finished
DEC 1
DUP
CBRANCH.NZ CARD_LOOP1
DROP ; remove outer loop count value
RET
CARD_OK:
DROP ; remove outer loop count value
; CMD16: set block size to 512 byte
LOADC 0
LOADC 512
LOADC 16
LOADCP SENDCMD_R1
CALL
DROP ; ignore return value
RET
; set fast transfer rate
CARDFASTCLK:
LOADC SPIREG
; set clock divider to ~2,6MHz
LOADCP SPI_CLK_DIV_WR,10 ; using the LOADCP with offset syntax here
STOREI
DROP
RET
; perform first phase of card initialization
; which is to enable clock and wait a bit
; leaves the clock running
_SPIINIT1:
LOADC SPIREG
; set clock divider to ~325KHz
LOADCP SPI_CLK_DIV_WR,64 ; LOADCP with offset
STOREI
DROP
; clear all flags + enable clock
; /CS and MOSI are default high
LOADC SPIREG
LOADCP SPI_CTRL_WRITE,SPI_CLK_F_EN
STOREI
DROP
; we should wait at least for 74 clock cycles now
LOADC 2 ; wait 2 msec, that should be ~300 cycles
_SPIINIT1L:
LOADCP WAIT1MSEC
CALL
DEC 1
DUP
CBRANCH.NZ _SPIINIT1L
DROP
LOADC SPIREG
LOADCP SPI_CTRL_WRITE ; disable clock
STOREI
DROP
LOADCP WAIT1MSEC
CALL
RET
; wait for transmission to finish
; (wait for TX_EMPTY bit)
_SPIWAITTX:
LOADC SPIREG
LOADI
LOADCP SPI_TX_EMPTY
AND
CBRANCH.Z _SPIWAITTX
RET
; finalize a command that has been sent:
; wait until the transmitter is idle
; then disable clock and set MOSI high
_SPIENDCMD:
LOADCP $FF
LOADCP _SENDBYTE
CALL
LOADCP $FF
LOADCP _SENDBYTE
CALL
;LOADC 'E'
;LOADCP CONOUT
;CALL
LOADCP _SPIWAITTX
CALL
;LOADC 'w'
;LOADCP CONOUT
;CALL
LOADCP _WAIT_S ; wait a short time
CALL
LOADC SPIREG
LOADCP SPI_IDLE_FLAGS ; turn off transceiver
LOADI
STOREI
DROP
; wait for a few instructions
LOADC 100
SPIEND_LP: DEC 1
DUP
CBRANCH.NZ SPIEND_LP
DROP
RET
_WAIT_S:
LOADC 100
_WAIT_S_L:
DEC 1
DUP
CBRANCH.NZ _WAIT_S_L
DROP
RET
; clear RX fifo
CLEAR_RX_FIFO:
CLEAR_RX_L1:
LOADC SPIREG
LOADI
;DUP
;LOADCP PRINTHEXW
;CALL
;LOADCP NEWLINE
;CALL
LOADC SPI_RX_AVAIL
AND
CBRANCH.Z CLEAR_RX_X
LOADC SPIREG
LOADC SPI_RX_RD
STOREI
DROP
; FIXME: it seems that this
; does not remove a byte from the fifo,
; rx_avail stays on, but only after the first
; byte has been received and read
;LOADC 'x'
;LOADCP CONOUT
;CALL
BRANCH CLEAR_RX_L1
CLEAR_RX_X:
RET
_WAITSPITXRDY:
LOADC SPIREG
LOADI
LOADCP SPI_TX_RDY
AND
CBRANCH.Z _WAITSPITXRDY
RET
; send a command and receive a data packet response
; args: packet size in words, buffer pointer
; checksum byte, 32-bit cmd arg, cmd number
; returns: 0 on success
SENDCMD_PKT:
; first send the command
LOADCP SENDCMD_0
CALL
LOADCP _RCVBYTE ; receive R1 response
CALL
CBRANCH.NZ SENDCMD_PKT_E ; on success we get 0
; now wait for data token
SENDCMD_PKT_L:
LOADCP _RCVBYTE
CALL
LOADC $FF
CMP EQ
CBRANCH SENDCMD_PKT_L
; parameters for _RCVWORDS are on the stack now
LOADCP _RCVWORDS
CALL
; receive 2 crc bytes
LOADCP _RCVBYTE
CALL
BROT
LOADCP _RCVBYTE
CALL
OR
; terminate command
LOADCP _SPIENDCMD
CALL
DROP ; we ignore the checksum for now
LOADC 0
RET
SENDCMD_PKT_E:
DROP ; remove remaining args
DROP
LOADC -1 ; return code for error
RET
; send a command and send a data packet
; args: packet size in words, buffer pointer
; checksum byte, 32-bit cmd arg, cmd number
; returns: 0 on success
SENDCMD_TXPKT:
; first send the command
LOADCP SENDCMD_0
CALL
;LOADCP _RCVBYTE
;CALL
;DROP ; remove byte received during transmit
LOADCP _RCVBYTE ; receive R1 response
CALL
CBRANCH.NZ SENDCMD_TXPKT_E ; on error we get nonzero
; send stuff byte
LOADC $FF
LOADCP _SENDBYTE
CALL
; now send data token
LOADCP %11111110
LOADCP _SENDBYTE
CALL
; send data block
; parameters for _SENDWORDS are on the stack now
LOADCP _SENDWORDS
CALL
; send 2 dummy crc bytes
LOADC 0
LOADCP _SENDBYTE
CALL
LOADC 0
LOADCP _SENDBYTE
CALL
;receive data response byte
SENDCMD_TXPKT_LR:
LOADCP _RCVBYTE
CALL
LOADC $FF ; discard $FF bytes
CMP.S0 NE
CBRANCH SENDCMD_TXPKT_CT
DROP
BRANCH SENDCMD_TXPKT_LR
SENDCMD_TXPKT_CT:
LOADC $1F
AND ; isolate status bits
LOADC $5 ; command accepted bit set?
CMP NE ; if not, exit with error
CBRANCH SENDCMD_TXPKT_E2
; wait until card is busy
SENDCMD_TXPKT_LB:
LOADCP _RCVBYTE ; receive byte
CALL
CBRANCH.NZ SENDCMD_TXPKT_LB ; loop until byte is 0
; wait until card is not busy
SENDCMD_TXPKT_L2:
LOADCP _RCVBYTE ;receive byte
CALL
CBRANCH.Z SENDCMD_TXPKT_L2 ; loop if byte is 0 (i.e. MISO is held low)
LOADC 0
BRANCH SENDCMD_TXPKT_X
SENDCMD_TXPKT_E:
DROP ; remove remaining args
DROP
SENDCMD_TXPKT_E2:
LOADC -1 ; return code for error
SENDCMD_TXPKT_X:
; terminate command
LOADCP _SPIENDCMD
CALL
RET
; send a command and receive a 1-byte-response (R1)
; args: checksum byte, 32-bit cmd arg, cmd number
; returns: received byte
SENDCMD_R1:
LOADCP SENDCMD_0
CALL
LOADCP _RCVBYTE
CALL
;LOADC 'R'
;LOADCP CONOUT
;CALL
;terminate command (/cs high, disable clock)
LOADCP _SPIENDCMD
CALL
RET
; send a command
; args: checksum byte, 32-bit cmd arg, cmd number
SENDCMD_0:
; clear RX FIFO first
LOADCP CLEAR_RX_FIFO
CALL
;LOADC '>'
;LOADCP CONOUT
;CALL
; cmd byte is at TOS at this point
LOADC $40 ; or in start of frame bit
OR
LOADCP _SENDBYTE
CALL
; cmd arg is at TOS now
LOADCP _SENDWORD
CALL
; checksum byte is at TOS now
LOADCP _SENDBYTE
CALL
LOADCP _XCVR_ENABLE ; enable transceiver last,
CALL ; a complete command should
RET ; fit into the tx fifo
; send ACMD and receive a 1-byte-response (R1)
; args: checksum byte, 32-bit cmd arg, ACMD number
; returns: received byte or -1 if first response byte
; indicated an error
SENDACMD_R1:
LOADC $0
LOADC $0
LOADC 55 ; send CMD55
LOADCP SENDCMD_R1
CALL
LOADC 1 ; 1 = idle state, no errors
CMP NE
CBRANCH.NZ SENDACMD_ERR
; pass our args to SENDCMD_R1
LOADCP SENDCMD_R1
CALL
RET
SENDACMD_ERR:
LOADCP -1
RET
; send a command and receive a 4+1-byte-response (R7)
; args: checksum byte, 32-bit cmd arg, cmd number
; returns: received word or -1 if first response byte
; indicated an error
SENDCMD_R7:
; send the command
LOADCP SENDCMD_0
CALL
;LOADC '7'
;LOADCP CONOUT
;CALL
LOADCP _RCVBYTE
CALL
LOADCP _RCVWORD
CALL
;terminate command (/cs high, disable clock)
LOADCP _SPIENDCMD
CALL
SWAP ; swap 1st response byte with received word
LOADC %011111110 ; check for any error flags
AND
CBRANCH.Z SENDCMD_R7_NOERR
DROP
LOADC -1
SENDCMD_R7_NOERR:
RET
; send a word as 4 bytes, msb first
_SENDWORD:
DUP ; remember original value for later
BROT ; rotate msb to lsb (byte 0)
LOADC 255
AND.S0 ; isolate byte, keep previous value
LOADCP _SENDBYTE
CALL
BROT ; byte 1
LOADC 255
AND.S0
LOADCP _SENDBYTE
CALL
BROT ; byte 2
LOADC 255
AND
LOADCP _SENDBYTE
CALL
; byte 3 is already on the stack
LOADC 255
AND
LOADCP _SENDBYTE
CALL
RET
; send multiple 4-byte-words
; args: number of words, pointer to buffer
_SENDWORDS:
FPADJ -4
STORE 0 ; store pointer arg into local variable
; keep counter on stack
_SENDWORDS_LP:
LOAD 0 ; load buf pointer
DUP ; duplicate it
INC 4 ; increment pointer
STORE 0 ; and store it back
LOADI ; load from previously duped pointer
LOADCP _SENDWORD
CALL ; send a word
DEC 1 ; decrement word counter
DUP
CBRANCH.NZ _SENDWORDS_LP ; if not null, loop
DROP ; remove counter value
FPADJ 4
RET
; receive multiple 4-byte-words and store into
; memory buffer
; args: number of words, pointer to buffer
_RCVWORDS:
FPADJ -4
STORE 0 ; store pointer arg into local variable
; keep counter on stack
_RCVWORDS_LP:
LOAD 0 ; load buf pointer for STOREI
LOADCP _RCVWORD
CALL ; receive a word
STOREI 4 ; store to buf with postincrement
STORE 0 ; store pointer variable
DEC 1 ; decrement word counter
DUP
CBRANCH.NZ _RCVWORDS_LP ; if not null, loop
DROP ; remove counter value
FPADJ 4
RET
; receive 4 bytes, return as word
_RCVWORD:
LOADCP _RCVBYTE ; receive first byte
CALL
BROT ; rotate byte to left
LOADCP _RCVBYTE ; receive second byte
CALL
OR ; or first and second byte together
BROT ; rotate 1st + 2nd to left
LOADCP _RCVBYTE ; receive third byte
CALL
OR
BROT
LOADCP _RCVBYTE ; receive fourth byte
CALL
OR
RET
_XCVR_ENABLE:
LOADC SPIREG
LOADCP SPI_TX_FLAGS
LOADI
STOREI
DROP
RET
; send a byte
; args: byte to be sent
_SENDBYTE:
LOADC SPIREG
LOADI ; load spi io register
LOADCP SPI_TX_RDY
AND ; check tx_rdy bit
CBRANCH.Z _SENDBYTE ; if not set, loop
LOADC SPI_TX_WR ; TX_WR bit
OR ; OR in byte to be send
LOADC SPIREG
SWAP ; swap value and addr for STOREI
STOREI ; store word (flags + data) to io register
DROP ; remove STOREI result
RET
; receive a byte. receiver must be enabled.
; returns: received byte
_RCVBYTE:
LOADC SPIREG
LOADI ; load spi io register
LOADC SPI_RX_AVAIL
AND.S0 ; check rx_avail bit, keep original value
CBRANCH.NZ RECV_GOTIT
DROP ; rx_avail not set, remove register value and loop
BRANCH _RCVBYTE
RECV_GOTIT:
LOADC SPIREG
LOADC SPI_RX_RD ; remove one byte from rx fifo
STOREI
DROP
LOADC 255
AND ; keep bits 7-0
RET
SPI_TX_FLAGS: .WORD SPI_CTRL_WRITE + SPI_TXRX_EN + SPI_RX_FILTER_EN
SPI_IDLE_FLAGS: .WORD SPI_CTRL_WRITE
.CPOOL
CSD_BUF: .BLOCK 4
CARD_BUF: .BLOCK 128

9181
lib/stdlib.s Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,218 @@
## This file is a general .xdc for the Arty A7-35 Rev. D
## To use it in a project:
## - uncomment the lines corresponding to used pins
## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project
## Clock signal
set_property -dict {PACKAGE_PIN E3 IOSTANDARD LVCMOS33} [get_ports clk]
create_clock -period 10.000 -name sys_clk_pin -waveform {0.000 5.000} -add [get_ports clk]
## Switches
set_property -dict {PACKAGE_PIN A8 IOSTANDARD LVCMOS33} [get_ports sw0]
set_property -dict {PACKAGE_PIN C11 IOSTANDARD LVCMOS33} [get_ports sw1]
#set_property -dict { PACKAGE_PIN C10 IOSTANDARD LVCMOS33 } [get_ports { sw[2] }]; #IO_L13N_T2_MRCC_16 Sch=sw[2]
#set_property -dict { PACKAGE_PIN A10 IOSTANDARD LVCMOS33 } [get_ports { sw[3] }]; #IO_L14P_T2_SRCC_16 Sch=sw[3]
## RGB LEDs
#set_property -dict { PACKAGE_PIN E1 IOSTANDARD LVCMOS33 } [get_ports { led0_b }]; #IO_L18N_T2_35 Sch=led0_b
#set_property -dict { PACKAGE_PIN F6 IOSTANDARD LVCMOS33 } [get_ports { led0_g }]; #IO_L19N_T3_VREF_35 Sch=led0_g
#set_property -dict { PACKAGE_PIN G6 IOSTANDARD LVCMOS33 } [get_ports { led0_r }]; #IO_L19P_T3_35 Sch=led0_r
#set_property -dict { PACKAGE_PIN G4 IOSTANDARD LVCMOS33 } [get_ports { led1_b }]; #IO_L20P_T3_35 Sch=led1_b
#set_property -dict { PACKAGE_PIN J4 IOSTANDARD LVCMOS33 } [get_ports { led1_g }]; #IO_L21P_T3_DQS_35 Sch=led1_g
#set_property -dict { PACKAGE_PIN G3 IOSTANDARD LVCMOS33 } [get_ports { led1_r }]; #IO_L20N_T3_35 Sch=led1_r
#set_property -dict { PACKAGE_PIN H4 IOSTANDARD LVCMOS33 } [get_ports { led2_b }]; #IO_L21N_T3_DQS_35 Sch=led2_b
#set_property -dict { PACKAGE_PIN J2 IOSTANDARD LVCMOS33 } [get_ports { led2_g }]; #IO_L22N_T3_35 Sch=led2_g
#set_property -dict { PACKAGE_PIN J3 IOSTANDARD LVCMOS33 } [get_ports { led2_r }]; #IO_L22P_T3_35 Sch=led2_r
#set_property -dict { PACKAGE_PIN K2 IOSTANDARD LVCMOS33 } [get_ports { led3_b }]; #IO_L23P_T3_35 Sch=led3_b
#set_property -dict { PACKAGE_PIN H6 IOSTANDARD LVCMOS33 } [get_ports { led3_g }]; #IO_L24P_T3_35 Sch=led3_g
#set_property -dict { PACKAGE_PIN K1 IOSTANDARD LVCMOS33 } [get_ports { led3_r }]; #IO_L23N_T3_35 Sch=led3_r
## LEDs
set_property -dict {PACKAGE_PIN H5 IOSTANDARD LVCMOS33} [get_ports led0]
set_property -dict {PACKAGE_PIN J5 IOSTANDARD LVCMOS33} [get_ports led1]
set_property -dict {PACKAGE_PIN T9 IOSTANDARD LVCMOS33} [get_ports led2]
set_property -dict {PACKAGE_PIN T10 IOSTANDARD LVCMOS33} [get_ports led3]
## Buttons
set_property -dict {PACKAGE_PIN D9 IOSTANDARD LVCMOS33} [get_ports btn0]
#set_property -dict { PACKAGE_PIN C9 IOSTANDARD LVCMOS33 } [get_ports { btn1 }]; #IO_L11P_T1_SRCC_16 Sch=btn[1]
#set_property -dict { PACKAGE_PIN B9 IOSTANDARD LVCMOS33 } [get_ports { btn[2] }]; #IO_L11N_T1_SRCC_16 Sch=btn[2]
#set_property -dict { PACKAGE_PIN B8 IOSTANDARD LVCMOS33 } [get_ports { btn[3] }]; #IO_L12P_T1_MRCC_16 Sch=btn[3]
## Pmod Header JA
set_property -dict {PACKAGE_PIN G13 IOSTANDARD LVCMOS33} [get_ports sd_cs_n]
set_property -dict {PACKAGE_PIN B11 IOSTANDARD LVCMOS33} [get_ports sd_mosi]
set_property -dict {PACKAGE_PIN A11 IOSTANDARD LVCMOS33} [get_ports sd_miso]
set_property -dict {PACKAGE_PIN D12 IOSTANDARD LVCMOS33} [get_ports sd_sck]
#set_property -dict { PACKAGE_PIN D13 IOSTANDARD LVCMOS33 } [get_ports { sd_dat1 }]; #IO_L6N_T0_VREF_15 Sch=ja[7]
#set_property -dict { PACKAGE_PIN B18 IOSTANDARD LVCMOS33 } [get_ports { sd_dat2 }]; #IO_L10P_T1_AD11P_15 Sch=ja[8]
set_property -dict {PACKAGE_PIN A18 IOSTANDARD LVCMOS33} [get_ports sd_cd]
#set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33 } [get_ports { sd_nc }]; #IO_25_15 Sch=ja[10]
###Pmod Header JB
set_property -dict {PACKAGE_PIN E15 IOSTANDARD LVCMOS33} [get_ports {VGA_R[0]}]
set_property -dict {PACKAGE_PIN E16 IOSTANDARD LVCMOS33} [get_ports {VGA_R[1]}]
set_property -dict {PACKAGE_PIN D15 IOSTANDARD LVCMOS33} [get_ports {VGA_R[2]}]
set_property -dict {PACKAGE_PIN C15 IOSTANDARD LVCMOS33} [get_ports {VGA_R[3]}]
set_property -dict {PACKAGE_PIN J17 IOSTANDARD LVCMOS33} [get_ports {VGA_B[0]}]
set_property -dict {PACKAGE_PIN J18 IOSTANDARD LVCMOS33} [get_ports {VGA_B[1]}]
set_property -dict {PACKAGE_PIN K15 IOSTANDARD LVCMOS33} [get_ports {VGA_B[2]}]
set_property -dict {PACKAGE_PIN J15 IOSTANDARD LVCMOS33} [get_ports {VGA_B[3]}]
###Pmod Header JC
set_property -dict {PACKAGE_PIN U12 IOSTANDARD LVCMOS33} [get_ports {VGA_G[0]}]
set_property -dict {PACKAGE_PIN V12 IOSTANDARD LVCMOS33} [get_ports {VGA_G[1]}]
set_property -dict {PACKAGE_PIN V10 IOSTANDARD LVCMOS33} [get_ports {VGA_G[2]}]
set_property -dict {PACKAGE_PIN V11 IOSTANDARD LVCMOS33} [get_ports {VGA_G[3]}]
set_property -dict {PACKAGE_PIN U14 IOSTANDARD LVCMOS33} [get_ports VGA_HS_O]
set_property -dict {PACKAGE_PIN V14 IOSTANDARD LVCMOS33} [get_ports VGA_VS_O]
#set_property -dict { PACKAGE_PIN T13 IOSTANDARD LVCMOS33 } [get_ports { jc[6] }]; #IO_L23P_T3_A03_D19_14 Sch=jc_p[4]
#set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33 } [get_ports { jc[7] }]; #IO_L23N_T3_A02_D18_14 Sch=jc_n[4]
## Pmod Header JD
#set_property -dict { PACKAGE_PIN D4 IOSTANDARD LVCMOS33 } [get_ports { jd[0] }]; #IO_L11N_T1_SRCC_35 Sch=jd[1]
#set_property -dict { PACKAGE_PIN D3 IOSTANDARD LVCMOS33 } [get_ports { jd[1] }]; #IO_L12N_T1_MRCC_35 Sch=jd[2]
#set_property -dict { PACKAGE_PIN F4 IOSTANDARD LVCMOS33 } [get_ports { jd[2] }]; #IO_L13P_T2_MRCC_35 Sch=jd[3]
#set_property -dict { PACKAGE_PIN F3 IOSTANDARD LVCMOS33 } [get_ports { jd[3] }]; #IO_L13N_T2_MRCC_35 Sch=jd[4]
#set_property -dict { PACKAGE_PIN E2 IOSTANDARD LVCMOS33 } [get_ports { jd[4] }]; #IO_L14P_T2_SRCC_35 Sch=jd[7]
#set_property -dict { PACKAGE_PIN D2 IOSTANDARD LVCMOS33 } [get_ports { jd[5] }]; #IO_L14N_T2_SRCC_35 Sch=jd[8]
#set_property -dict { PACKAGE_PIN H2 IOSTANDARD LVCMOS33 } [get_ports { jd[6] }]; #IO_L15P_T2_DQS_35 Sch=jd[9]
#set_property -dict { PACKAGE_PIN G2 IOSTANDARD LVCMOS33 } [get_ports { jd[7] }]; #IO_L15N_T2_DQS_35 Sch=jd[10]
## USB-UART Interface
set_property -dict {PACKAGE_PIN D10 IOSTANDARD LVCMOS33} [get_ports uart_rxd_out]
set_property -dict {PACKAGE_PIN A9 IOSTANDARD LVCMOS33} [get_ports uart_txd_in]
## ChipKit Outer Digital Header
#set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { ck_io0 }]; #IO_L16P_T2_CSI_B_14 Sch=ck_io[0]
#set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports { ck_io1 }]; #IO_L18P_T2_A12_D28_14 Sch=ck_io[1]
#set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { ck_io2 }]; #IO_L8N_T1_D12_14 Sch=ck_io[2]
#set_property -dict { PACKAGE_PIN T11 IOSTANDARD LVCMOS33 } [get_ports { ck_io3 }]; #IO_L19P_T3_A10_D26_14 Sch=ck_io[3]
#set_property -dict { PACKAGE_PIN R12 IOSTANDARD LVCMOS33 } [get_ports { ck_io4 }]; #IO_L5P_T0_D06_14 Sch=ck_io[4]
#set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { ck_io5 }]; #IO_L14P_T2_SRCC_14 Sch=ck_io[5]
#set_property -dict { PACKAGE_PIN T15 IOSTANDARD LVCMOS33 } [get_ports { ck_io6 }]; #IO_L14N_T2_SRCC_14 Sch=ck_io[6]
#set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS33 } [get_ports { ck_io7 }]; #IO_L15N_T2_DQS_DOUT_CSO_B_14 Sch=ck_io[7]
#set_property -dict { PACKAGE_PIN N15 IOSTANDARD LVCMOS33 } [get_ports { ck_io8 }]; #IO_L11P_T1_SRCC_14 Sch=ck_io[8]
#set_property -dict { PACKAGE_PIN M16 IOSTANDARD LVCMOS33 } [get_ports { ck_io9 }]; #IO_L10P_T1_D14_14 Sch=ck_io[9]
#set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { ck_io10 }]; #IO_L18N_T2_A11_D27_14 Sch=ck_io[10]
#set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { ck_io11 }]; #IO_L17N_T2_A13_D29_14 Sch=ck_io[11]
#set_property -dict { PACKAGE_PIN R17 IOSTANDARD LVCMOS33 } [get_ports { ck_io12 }]; #IO_L12N_T1_MRCC_14 Sch=ck_io[12]
#set_property -dict { PACKAGE_PIN P17 IOSTANDARD LVCMOS33 } [get_ports { ck_io13 }]; #IO_L12P_T1_MRCC_14 Sch=ck_io[13]
## ChipKit Inner Digital Header
#set_property -dict { PACKAGE_PIN U11 IOSTANDARD LVCMOS33 } [get_ports { ck_io26 }]; #IO_L19N_T3_A09_D25_VREF_14 Sch=ck_io[26]
#set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { ck_io27 }]; #IO_L16N_T2_A15_D31_14 Sch=ck_io[27]
#set_property -dict { PACKAGE_PIN M13 IOSTANDARD LVCMOS33 } [get_ports { ck_io28 }]; #IO_L6N_T0_D08_VREF_14 Sch=ck_io[28]
#set_property -dict { PACKAGE_PIN R10 IOSTANDARD LVCMOS33 } [get_ports { ck_io29 }]; #IO_25_14 Sch=ck_io[29]
#set_property -dict { PACKAGE_PIN R11 IOSTANDARD LVCMOS33 } [get_ports { ck_io30 }]; #IO_0_14 Sch=ck_io[30]
#set_property -dict { PACKAGE_PIN R13 IOSTANDARD LVCMOS33 } [get_ports { ck_io31 }]; #IO_L5N_T0_D07_14 Sch=ck_io[31]
#set_property -dict { PACKAGE_PIN R15 IOSTANDARD LVCMOS33 } [get_ports { ck_io32 }]; #IO_L13N_T2_MRCC_14 Sch=ck_io[32]
#set_property -dict { PACKAGE_PIN P15 IOSTANDARD LVCMOS33 } [get_ports { ck_io33 }]; #IO_L13P_T2_MRCC_14 Sch=ck_io[33]
#set_property -dict { PACKAGE_PIN R16 IOSTANDARD LVCMOS33 } [get_ports { ck_io34 }]; #IO_L15P_T2_DQS_RDWR_B_14 Sch=ck_io[34]
#set_property -dict { PACKAGE_PIN N16 IOSTANDARD LVCMOS33 } [get_ports { ck_io35 }]; #IO_L11N_T1_SRCC_14 Sch=ck_io[35]
#set_property -dict { PACKAGE_PIN N14 IOSTANDARD LVCMOS33 } [get_ports { ck_io36 }]; #IO_L8P_T1_D11_14 Sch=ck_io[36]
#set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports { ck_io37 }]; #IO_L17P_T2_A14_D30_14 Sch=ck_io[37]
#set_property -dict { PACKAGE_PIN T18 IOSTANDARD LVCMOS33 } [get_ports { ck_io38 }]; #IO_L7N_T1_D10_14 Sch=ck_io[38]
#set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { ck_io39 }]; #IO_L7P_T1_D09_14 Sch=ck_io[39]
#set_property -dict { PACKAGE_PIN P18 IOSTANDARD LVCMOS33 } [get_ports { ck_io40 }]; #IO_L9N_T1_DQS_D13_14 Sch=ck_io[40]
#set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports { ck_io41 }]; #IO_L9P_T1_DQS_14 Sch=ck_io[41]
## ChipKit Outer Analog Header - as Single-Ended Analog Inputs
## NOTE: These ports can be used as single-ended analog inputs with voltages from 0-3.3V (ChipKit analog pins A0-A5) or as digital I/O.
## WARNING: Do not use both sets of constraints at the same time!
## NOTE: The following constraints should be used with the XADC IP core when using these ports as analog inputs.
#set_property -dict { PACKAGE_PIN C5 IOSTANDARD LVCMOS33 } [get_ports { vaux4_n }]; #IO_L1N_T0_AD4N_35 Sch=ck_an_n[0] ChipKit pin=A0
#set_property -dict { PACKAGE_PIN C6 IOSTANDARD LVCMOS33 } [get_ports { vaux4_p }]; #IO_L1P_T0_AD4P_35 Sch=ck_an_p[0] ChipKit pin=A0
#set_property -dict { PACKAGE_PIN A5 IOSTANDARD LVCMOS33 } [get_ports { vaux5_n }]; #IO_L3N_T0_DQS_AD5N_35 Sch=ck_an_n[1] ChipKit pin=A1
#set_property -dict { PACKAGE_PIN A6 IOSTANDARD LVCMOS33 } [get_ports { vaux5_p }]; #IO_L3P_T0_DQS_AD5P_35 Sch=ck_an_p[1] ChipKit pin=A1
#set_property -dict { PACKAGE_PIN B4 IOSTANDARD LVCMOS33 } [get_ports { vaux6_n }]; #IO_L7N_T1_AD6N_35 Sch=ck_an_n[2] ChipKit pin=A2
#set_property -dict { PACKAGE_PIN C4 IOSTANDARD LVCMOS33 } [get_ports { vaux6_p }]; #IO_L7P_T1_AD6P_35 Sch=ck_an_p[2] ChipKit pin=A2
#set_property -dict { PACKAGE_PIN A1 IOSTANDARD LVCMOS33 } [get_ports { vaux7_n }]; #IO_L9N_T1_DQS_AD7N_35 Sch=ck_an_n[3] ChipKit pin=A3
#set_property -dict { PACKAGE_PIN B1 IOSTANDARD LVCMOS33 } [get_ports { vaux7_p }]; #IO_L9P_T1_DQS_AD7P_35 Sch=ck_an_p[3] ChipKit pin=A3
#set_property -dict { PACKAGE_PIN B2 IOSTANDARD LVCMOS33 } [get_ports { vaux15_n }]; #IO_L10N_T1_AD15N_35 Sch=ck_an_n[4] ChipKit pin=A4
#set_property -dict { PACKAGE_PIN B3 IOSTANDARD LVCMOS33 } [get_ports { vaux15_p }]; #IO_L10P_T1_AD15P_35 Sch=ck_an_p[4] ChipKit pin=A4
#set_property -dict { PACKAGE_PIN C14 IOSTANDARD LVCMOS33 } [get_ports { vaux0_n }]; #IO_L1N_T0_AD0N_15 Sch=ck_an_n[5] ChipKit pin=A5
#set_property -dict { PACKAGE_PIN D14 IOSTANDARD LVCMOS33 } [get_ports { vaux0_p }]; #IO_L1P_T0_AD0P_15 Sch=ck_an_p[5] ChipKit pin=A5
## ChipKit Outer Analog Header - as Digital I/O
## NOTE: the following constraints should be used when using these ports as digital I/O.
#set_property -dict { PACKAGE_PIN F5 IOSTANDARD LVCMOS33 } [get_ports { ck_a0 }]; #IO_0_35 Sch=ck_a[0] ChipKit pin=A0
#set_property -dict { PACKAGE_PIN D8 IOSTANDARD LVCMOS33 } [get_ports { ck_a1 }]; #IO_L4P_T0_35 Sch=ck_a[1] ChipKit pin=A1
#set_property -dict { PACKAGE_PIN C7 IOSTANDARD LVCMOS33 } [get_ports { ck_a2 }]; #IO_L4N_T0_35 Sch=ck_a[2] ChipKit pin=A2
#set_property -dict { PACKAGE_PIN E7 IOSTANDARD LVCMOS33 } [get_ports { ck_a3 }]; #IO_L6P_T0_35 Sch=ck_a[3] ChipKit pin=A3
#set_property -dict { PACKAGE_PIN D7 IOSTANDARD LVCMOS33 } [get_ports { ck_a4 }]; #IO_L6N_T0_VREF_35 Sch=ck_a[4] ChipKit pin=A4
#set_property -dict { PACKAGE_PIN D5 IOSTANDARD LVCMOS33 } [get_ports { ck_a5 }]; #IO_L11P_T1_SRCC_35 Sch=ck_a[5] ChipKit pin=A5
## ChipKit Inner Analog Header - as Differential Analog Inputs
## NOTE: These ports can be used as differential analog inputs with voltages from 0-1.0V (ChipKit Analog pins A6-A11) or as digital I/O.
## WARNING: Do not use both sets of constraints at the same time!
## NOTE: The following constraints should be used with the XADC core when using these ports as analog inputs.
#set_property -dict { PACKAGE_PIN B7 IOSTANDARD LVCMOS33 } [get_ports { vaux12_p }]; #IO_L2P_T0_AD12P_35 Sch=ad_p[12] ChipKit pin=A6
#set_property -dict { PACKAGE_PIN B6 IOSTANDARD LVCMOS33 } [get_ports { vaux12_n }]; #IO_L2N_T0_AD12N_35 Sch=ad_n[12] ChipKit pin=A7
#set_property -dict { PACKAGE_PIN E6 IOSTANDARD LVCMOS33 } [get_ports { vaux13_p }]; #IO_L5P_T0_AD13P_35 Sch=ad_p[13] ChipKit pin=A8
#set_property -dict { PACKAGE_PIN E5 IOSTANDARD LVCMOS33 } [get_ports { vaux13_n }]; #IO_L5N_T0_AD13N_35 Sch=ad_n[13] ChipKit pin=A9
#set_property -dict { PACKAGE_PIN A4 IOSTANDARD LVCMOS33 } [get_ports { vaux14_p }]; #IO_L8P_T1_AD14P_35 Sch=ad_p[14] ChipKit pin=A10
#set_property -dict { PACKAGE_PIN A3 IOSTANDARD LVCMOS33 } [get_ports { vaux14_n }]; #IO_L8N_T1_AD14N_35 Sch=ad_n[14] ChipKit pin=A11
## ChipKit Inner Analog Header - as Digital I/O
## NOTE: the following constraints should be used when using the inner analog header ports as digital I/O.
#set_property -dict { PACKAGE_PIN B7 IOSTANDARD LVCMOS33 } [get_ports { ck_io20 }]; #IO_L2P_T0_AD12P_35 Sch=ad_p[12] ChipKit pin=A6
#set_property -dict { PACKAGE_PIN B6 IOSTANDARD LVCMOS33 } [get_ports { ck_io21 }]; #IO_L2N_T0_AD12N_35 Sch=ad_n[12] ChipKit pin=A7
#set_property -dict { PACKAGE_PIN E6 IOSTANDARD LVCMOS33 } [get_ports { ck_io22 }]; #IO_L5P_T0_AD13P_35 Sch=ad_p[13] ChipKit pin=A8
#set_property -dict { PACKAGE_PIN E5 IOSTANDARD LVCMOS33 } [get_ports { ck_io23 }]; #IO_L5N_T0_AD13N_35 Sch=ad_n[13] ChipKit pin=A9
#set_property -dict { PACKAGE_PIN A4 IOSTANDARD LVCMOS33 } [get_ports { ck_io24 }]; #IO_L8P_T1_AD14P_35 Sch=ad_p[14] ChipKit pin=A10
#set_property -dict { PACKAGE_PIN A3 IOSTANDARD LVCMOS33 } [get_ports { ck_io25 }]; #IO_L8N_T1_AD14N_35 Sch=ad_n[14] ChipKit pin=A11
## ChipKit SPI
#set_property -dict { PACKAGE_PIN G1 IOSTANDARD LVCMOS33 } [get_ports { ck_miso }]; #IO_L17N_T2_35 Sch=ck_miso
#set_property -dict { PACKAGE_PIN H1 IOSTANDARD LVCMOS33 } [get_ports { ck_mosi }]; #IO_L17P_T2_35 Sch=ck_mosi
#set_property -dict { PACKAGE_PIN F1 IOSTANDARD LVCMOS33 } [get_ports { ck_sck }]; #IO_L18P_T2_35 Sch=ck_sck
#set_property -dict { PACKAGE_PIN C1 IOSTANDARD LVCMOS33 } [get_ports { ck_ss }]; #IO_L16N_T2_35 Sch=ck_ss
## ChipKit I2C
#set_property -dict { PACKAGE_PIN L18 IOSTANDARD LVCMOS33 } [get_ports { ck_scl }]; #IO_L4P_T0_D04_14 Sch=ck_scl
#set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { ck_sda }]; #IO_L4N_T0_D05_14 Sch=ck_sda
#set_property -dict { PACKAGE_PIN A14 IOSTANDARD LVCMOS33 } [get_ports { scl_pup }]; #IO_L9N_T1_DQS_AD3N_15 Sch=scl_pup
#set_property -dict { PACKAGE_PIN A13 IOSTANDARD LVCMOS33 } [get_ports { sda_pup }]; #IO_L9P_T1_DQS_AD3P_15 Sch=sda_pup
## Misc. ChipKit Ports
#set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS33 } [get_ports { ck_ioa }]; #IO_L10N_T1_D15_14 Sch=ck_ioa
set_property -dict {PACKAGE_PIN C2 IOSTANDARD LVCMOS33} [get_ports rst]
## SMSC Ethernet PHY
#set_property -dict { PACKAGE_PIN D17 IOSTANDARD LVCMOS33 } [get_ports { eth_col }]; #IO_L16N_T2_A27_15 Sch=eth_col
#set_property -dict { PACKAGE_PIN G14 IOSTANDARD LVCMOS33 } [get_ports { eth_crs }]; #IO_L15N_T2_DQS_ADV_B_15 Sch=eth_crs
#set_property -dict { PACKAGE_PIN F16 IOSTANDARD LVCMOS33 } [get_ports { eth_mdc }]; #IO_L14N_T2_SRCC_15 Sch=eth_mdc
#set_property -dict { PACKAGE_PIN K13 IOSTANDARD LVCMOS33 } [get_ports { eth_mdio }]; #IO_L17P_T2_A26_15 Sch=eth_mdio
#set_property -dict { PACKAGE_PIN G18 IOSTANDARD LVCMOS33 } [get_ports { eth_ref_clk }]; #IO_L22P_T3_A17_15 Sch=eth_ref_clk
#set_property -dict { PACKAGE_PIN C16 IOSTANDARD LVCMOS33 } [get_ports { eth_rstn }]; #IO_L20P_T3_A20_15 Sch=eth_rstn
#set_property -dict { PACKAGE_PIN F15 IOSTANDARD LVCMOS33 } [get_ports { eth_rx_clk }]; #IO_L14P_T2_SRCC_15 Sch=eth_rx_clk
#set_property -dict { PACKAGE_PIN G16 IOSTANDARD LVCMOS33 } [get_ports { eth_rx_dv }]; #IO_L13N_T2_MRCC_15 Sch=eth_rx_dv
#set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[0] }]; #IO_L21N_T3_DQS_A18_15 Sch=eth_rxd[0]
#set_property -dict { PACKAGE_PIN E17 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[1] }]; #IO_L16P_T2_A28_15 Sch=eth_rxd[1]
#set_property -dict { PACKAGE_PIN E18 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[2] }]; #IO_L21P_T3_DQS_15 Sch=eth_rxd[2]
#set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[3] }]; #IO_L18N_T2_A23_15 Sch=eth_rxd[3]
#set_property -dict { PACKAGE_PIN C17 IOSTANDARD LVCMOS33 } [get_ports { eth_rxerr }]; #IO_L20N_T3_A19_15 Sch=eth_rxerr
#set_property -dict { PACKAGE_PIN H16 IOSTANDARD LVCMOS33 } [get_ports { eth_tx_clk }]; #IO_L13P_T2_MRCC_15 Sch=eth_tx_clk
#set_property -dict { PACKAGE_PIN H15 IOSTANDARD LVCMOS33 } [get_ports { eth_tx_en }]; #IO_L19N_T3_A21_VREF_15 Sch=eth_tx_en
#set_property -dict { PACKAGE_PIN H14 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[0] }]; #IO_L15P_T2_DQS_15 Sch=eth_txd[0]
#set_property -dict { PACKAGE_PIN J14 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[1] }]; #IO_L19P_T3_A22_15 Sch=eth_txd[1]
#set_property -dict { PACKAGE_PIN J13 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[2] }]; #IO_L17N_T2_A25_15 Sch=eth_txd[2]
#set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[3] }]; #IO_L18P_T2_A24_15 Sch=eth_txd[3]
## Quad SPI Flash
#set_property -dict { PACKAGE_PIN L13 IOSTANDARD LVCMOS33 } [get_ports { qspi_cs }]; #IO_L6P_T0_FCS_B_14 Sch=qspi_cs
#set_property -dict { PACKAGE_PIN K17 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[0] }]; #IO_L1P_T0_D00_MOSI_14 Sch=qspi_dq[0]
#set_property -dict { PACKAGE_PIN K18 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[1] }]; #IO_L1N_T0_D01_DIN_14 Sch=qspi_dq[1]
#set_property -dict { PACKAGE_PIN L14 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[2] }]; #IO_L2P_T0_D02_14 Sch=qspi_dq[2]
#set_property -dict { PACKAGE_PIN M14 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[3] }]; #IO_L2N_T0_D03_14 Sch=qspi_dq[3]
## Power Measurements
#set_property -dict { PACKAGE_PIN B17 IOSTANDARD LVCMOS33 } [get_ports { vsnsvu_n }]; #IO_L7N_T1_AD2N_15 Sch=ad_n[2]
#set_property -dict { PACKAGE_PIN B16 IOSTANDARD LVCMOS33 } [get_ports { vsnsvu_p }]; #IO_L7P_T1_AD2P_15 Sch=ad_p[2]
#set_property -dict { PACKAGE_PIN B12 IOSTANDARD LVCMOS33 } [get_ports { vsns5v0_n }]; #IO_L3N_T0_DQS_AD1N_15 Sch=ad_n[1]
#set_property -dict { PACKAGE_PIN C12 IOSTANDARD LVCMOS33 } [get_ports { vsns5v0_p }]; #IO_L3P_T0_DQS_AD1P_15 Sch=ad_p[1]
#set_property -dict { PACKAGE_PIN F14 IOSTANDARD LVCMOS33 } [get_ports { isns5v0_n }]; #IO_L5N_T0_AD9N_15 Sch=ad_n[9]
#set_property -dict { PACKAGE_PIN F13 IOSTANDARD LVCMOS33 } [get_ports { isns5v0_p }]; #IO_L5P_T0_AD9P_15 Sch=ad_p[9]
#set_property -dict { PACKAGE_PIN A16 IOSTANDARD LVCMOS33 } [get_ports { isns0v95_n }]; #IO_L8N_T1_AD10N_15 Sch=ad_n[10]
#set_property -dict { PACKAGE_PIN A15 IOSTANDARD LVCMOS33 } [get_ports { isns0v95_p }]; #IO_L8P_T1_AD10P_15 Sch=ad_p[10]
set_property BITSTREAM.GENERAL.COMPRESS True [current_design]

View file

@ -0,0 +1,48 @@
NET "ddr3_dq[0]" LOC = "K5" | IOSTANDARD = SSTL135 ;
NET "ddr3_dq[1]" LOC = "L3" | IOSTANDARD = SSTL135 ;
NET "ddr3_dq[2]" LOC = "K3" | IOSTANDARD = SSTL135 ;
NET "ddr3_dq[3]" LOC = "L6" | IOSTANDARD = SSTL135 ;
NET "ddr3_dq[4]" LOC = "M3" | IOSTANDARD = SSTL135 ;
NET "ddr3_dq[5]" LOC = "M1" | IOSTANDARD = SSTL135 ;
NET "ddr3_dq[6]" LOC = "L4" | IOSTANDARD = SSTL135 ;
NET "ddr3_dq[7]" LOC = "M2" | IOSTANDARD = SSTL135 ;
NET "ddr3_dq[8]" LOC = "V4" | IOSTANDARD = SSTL135 ;
NET "ddr3_dq[9]" LOC = "T5" | IOSTANDARD = SSTL135 ;
NET "ddr3_dq[10]" LOC = "U4" | IOSTANDARD = SSTL135 ;
NET "ddr3_dq[11]" LOC = "V5" | IOSTANDARD = SSTL135 ;
NET "ddr3_dq[12]" LOC = "V1" | IOSTANDARD = SSTL135 ;
NET "ddr3_dq[13]" LOC = "T3" | IOSTANDARD = SSTL135 ;
NET "ddr3_dq[14]" LOC = "U3" | IOSTANDARD = SSTL135 ;
NET "ddr3_dq[15]" LOC = "R3" | IOSTANDARD = SSTL135 ;
NET "ddr3_dm[0]" LOC = "L1" | IOSTANDARD = SSTL135 ;
NET "ddr3_dm[1]" LOC = "U1" | IOSTANDARD = SSTL135 ;
NET "ddr3_dqs_p[0]" LOC = "N2" | IOSTANDARD = DIFF_SSTL135 ;
NET "ddr3_dqs_n[0]" LOC = "N1" | IOSTANDARD = DIFF_SSTL135 ;
NET "ddr3_dqs_p[1]" LOC = "U2" | IOSTANDARD = DIFF_SSTL135 ;
NET "ddr3_dqs_n[1]" LOC = "V2" | IOSTANDARD = DIFF_SSTL135 ;
NET "ddr3_addr[13]" LOC = "T8" | IOSTANDARD = SSTL135 ;
NET "ddr3_addr[12]" LOC = "T6" | IOSTANDARD = SSTL135 ;
NET "ddr3_addr[11]" LOC = "U6" | IOSTANDARD = SSTL135 ;
NET "ddr3_addr[10]" LOC = "R6" | IOSTANDARD = SSTL135 ;
NET "ddr3_addr[9]" LOC = "V7" | IOSTANDARD = SSTL135 ;
NET "ddr3_addr[8]" LOC = "R8" | IOSTANDARD = SSTL135 ;
NET "ddr3_addr[7]" LOC = "U7" | IOSTANDARD = SSTL135 ;
NET "ddr3_addr[6]" LOC = "V6" | IOSTANDARD = SSTL135 ;
NET "ddr3_addr[5]" LOC = "R7" | IOSTANDARD = SSTL135 ;
NET "ddr3_addr[4]" LOC = "N6" | IOSTANDARD = SSTL135 ;
NET "ddr3_addr[3]" LOC = "T1" | IOSTANDARD = SSTL135 ;
NET "ddr3_addr[2]" LOC = "N4" | IOSTANDARD = SSTL135 ;
NET "ddr3_addr[1]" LOC = "M6" | IOSTANDARD = SSTL135 ;
NET "ddr3_addr[0]" LOC = "R2" | IOSTANDARD = SSTL135 ;
NET "ddr3_ba[2]" LOC = "P2" | IOSTANDARD = SSTL135 ;
NET "ddr3_ba[1]" LOC = "P4" | IOSTANDARD = SSTL135 ;
NET "ddr3_ba[0]" LOC = "R1" | IOSTANDARD = SSTL135 ;
NET "ddr3_ck_p[0]" LOC = "U9" | IOSTANDARD = DIFF_SSTL135 ;
NET "ddr3_ck_n[0]" LOC = "V9" | IOSTANDARD = DIFF_SSTL135 ;
NET "ddr3_ras_n" LOC = "P3" | IOSTANDARD = SSTL135 ;
NET "ddr3_cas_n" LOC = "M4" | IOSTANDARD = SSTL135 ;
NET "ddr3_we_n" LOC = "P5" | IOSTANDARD = SSTL135 ;
NET "ddr3_reset_n" LOC = "K6" | IOSTANDARD = SSTL135 ;
NET "ddr3_cke[0]" LOC = "N5" | IOSTANDARD = SSTL135 ;
NET "ddr3_odt[0]" LOC = "R5" | IOSTANDARD = SSTL135 ;
NET "ddr3_cs_n[0]" LOC = "U8" | IOSTANDARD = SSTL135 ;

View file

@ -0,0 +1,148 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Project NoOfControllers="1">
<!-- IMPORTANT: This is an internal file that has been generated by the MIG software. Any direct editing or changes made to this file may result in unpredictable behavior or data corruption. It is strongly advised that users do not edit the contents of this file. Re-run the MIG GUI with the required settings if any of the options provided below need to be altered. -->
<ModuleName>mig_dram_0</ModuleName>
<dci_inouts_inputs>1</dci_inouts_inputs>
<dci_inputs>1</dci_inputs>
<Debug_En>OFF</Debug_En>
<DataDepth_En>1024</DataDepth_En>
<LowPower_En>ON</LowPower_En>
<XADC_En>Enabled</XADC_En>
<TargetFPGA>xc7a35ti-csg324/-1L</TargetFPGA>
<Version>4.2</Version>
<SystemClock>No Buffer</SystemClock>
<ReferenceClock>No Buffer</ReferenceClock>
<SysResetPolarity>ACTIVE LOW</SysResetPolarity>
<BankSelectionFlag>FALSE</BankSelectionFlag>
<InternalVref>1</InternalVref>
<dci_hr_inouts_inputs>50 Ohms</dci_hr_inouts_inputs>
<dci_cascade>0</dci_cascade>
<Controller number="0">
<MemoryDevice>DDR3_SDRAM/Components/MT41K128M16XX-15E</MemoryDevice>
<TimePeriod>3000</TimePeriod>
<VccAuxIO>1.8V</VccAuxIO>
<PHYRatio>4:1</PHYRatio>
<InputClkFreq>83.333</InputClkFreq>
<UIExtraClocks>0</UIExtraClocks>
<MMCM_VCO>666</MMCM_VCO>
<MMCMClkOut0> 1.000</MMCMClkOut0>
<MMCMClkOut1>1</MMCMClkOut1>
<MMCMClkOut2>1</MMCMClkOut2>
<MMCMClkOut3>1</MMCMClkOut3>
<MMCMClkOut4>1</MMCMClkOut4>
<DataWidth>16</DataWidth>
<DeepMemory>1</DeepMemory>
<DataMask>1</DataMask>
<ECC>Disabled</ECC>
<Ordering>Strict</Ordering>
<BankMachineCnt>4</BankMachineCnt>
<CustomPart>FALSE</CustomPart>
<NewPartName/>
<RowAddress>14</RowAddress>
<ColAddress>10</ColAddress>
<BankAddress>3</BankAddress>
<MemoryVoltage>1.35V</MemoryVoltage>
<UserMemoryAddressMap>BANK_ROW_COLUMN</UserMemoryAddressMap>
<PinSelection>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="R2" SLEW="" VCCAUX_IO="" name="ddr3_addr[0]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="R6" SLEW="" VCCAUX_IO="" name="ddr3_addr[10]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="U6" SLEW="" VCCAUX_IO="" name="ddr3_addr[11]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="T6" SLEW="" VCCAUX_IO="" name="ddr3_addr[12]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="T8" SLEW="" VCCAUX_IO="" name="ddr3_addr[13]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="M6" SLEW="" VCCAUX_IO="" name="ddr3_addr[1]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="N4" SLEW="" VCCAUX_IO="" name="ddr3_addr[2]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="T1" SLEW="" VCCAUX_IO="" name="ddr3_addr[3]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="N6" SLEW="" VCCAUX_IO="" name="ddr3_addr[4]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="R7" SLEW="" VCCAUX_IO="" name="ddr3_addr[5]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="V6" SLEW="" VCCAUX_IO="" name="ddr3_addr[6]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="U7" SLEW="" VCCAUX_IO="" name="ddr3_addr[7]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="R8" SLEW="" VCCAUX_IO="" name="ddr3_addr[8]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="V7" SLEW="" VCCAUX_IO="" name="ddr3_addr[9]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="R1" SLEW="" VCCAUX_IO="" name="ddr3_ba[0]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="P4" SLEW="" VCCAUX_IO="" name="ddr3_ba[1]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="P2" SLEW="" VCCAUX_IO="" name="ddr3_ba[2]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="M4" SLEW="" VCCAUX_IO="" name="ddr3_cas_n"/>
<Pin IN_TERM="" IOSTANDARD="DIFF_SSTL135" PADName="V9" SLEW="" VCCAUX_IO="" name="ddr3_ck_n[0]"/>
<Pin IN_TERM="" IOSTANDARD="DIFF_SSTL135" PADName="U9" SLEW="" VCCAUX_IO="" name="ddr3_ck_p[0]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="N5" SLEW="" VCCAUX_IO="" name="ddr3_cke[0]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="U8" SLEW="" VCCAUX_IO="" name="ddr3_cs_n[0]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="L1" SLEW="" VCCAUX_IO="" name="ddr3_dm[0]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="U1" SLEW="" VCCAUX_IO="" name="ddr3_dm[1]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="K5" SLEW="" VCCAUX_IO="" name="ddr3_dq[0]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="U4" SLEW="" VCCAUX_IO="" name="ddr3_dq[10]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="V5" SLEW="" VCCAUX_IO="" name="ddr3_dq[11]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="V1" SLEW="" VCCAUX_IO="" name="ddr3_dq[12]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="T3" SLEW="" VCCAUX_IO="" name="ddr3_dq[13]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="U3" SLEW="" VCCAUX_IO="" name="ddr3_dq[14]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="R3" SLEW="" VCCAUX_IO="" name="ddr3_dq[15]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="L3" SLEW="" VCCAUX_IO="" name="ddr3_dq[1]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="K3" SLEW="" VCCAUX_IO="" name="ddr3_dq[2]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="L6" SLEW="" VCCAUX_IO="" name="ddr3_dq[3]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="M3" SLEW="" VCCAUX_IO="" name="ddr3_dq[4]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="M1" SLEW="" VCCAUX_IO="" name="ddr3_dq[5]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="L4" SLEW="" VCCAUX_IO="" name="ddr3_dq[6]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="M2" SLEW="" VCCAUX_IO="" name="ddr3_dq[7]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="V4" SLEW="" VCCAUX_IO="" name="ddr3_dq[8]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="T5" SLEW="" VCCAUX_IO="" name="ddr3_dq[9]"/>
<Pin IN_TERM="" IOSTANDARD="DIFF_SSTL135" PADName="N1" SLEW="" VCCAUX_IO="" name="ddr3_dqs_n[0]"/>
<Pin IN_TERM="" IOSTANDARD="DIFF_SSTL135" PADName="V2" SLEW="" VCCAUX_IO="" name="ddr3_dqs_n[1]"/>
<Pin IN_TERM="" IOSTANDARD="DIFF_SSTL135" PADName="N2" SLEW="" VCCAUX_IO="" name="ddr3_dqs_p[0]"/>
<Pin IN_TERM="" IOSTANDARD="DIFF_SSTL135" PADName="U2" SLEW="" VCCAUX_IO="" name="ddr3_dqs_p[1]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="R5" SLEW="" VCCAUX_IO="" name="ddr3_odt[0]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="P3" SLEW="" VCCAUX_IO="" name="ddr3_ras_n"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="K6" SLEW="" VCCAUX_IO="" name="ddr3_reset_n"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="P5" SLEW="" VCCAUX_IO="" name="ddr3_we_n"/>
</PinSelection>
<System_Control>
<Pin Bank="Select Bank" PADName="No connect" name="sys_rst"/>
<Pin Bank="Select Bank" PADName="No connect" name="init_calib_complete"/>
<Pin Bank="Select Bank" PADName="No connect" name="tg_compare_error"/>
</System_Control>
<TimingParameters>
<Parameters tcke="5.625" tfaw="45" tras="36" trcd="13.5" trefi="7.8" trfc="160" trp="13.5" trrd="7.5" trtp="7.5" twtr="7.5"/>
</TimingParameters>
<mrBurstLength name="Burst Length">8 - Fixed</mrBurstLength>
<mrBurstType name="Read Burst Type and Length">Sequential</mrBurstType>
<mrCasLatency name="CAS Latency">5</mrCasLatency>
<mrMode name="Mode">Normal</mrMode>
<mrDllReset name="DLL Reset">No</mrDllReset>
<mrPdMode name="DLL control for precharge PD">Slow Exit</mrPdMode>
<emrDllEnable name="DLL Enable">Enable</emrDllEnable>
<emrOutputDriveStrength name="Output Driver Impedance Control">RZQ/6</emrOutputDriveStrength>
<emrMirrorSelection name="Address Mirroring">Disable</emrMirrorSelection>
<emrCSSelection name="Controller Chip Select Pin">Enable</emrCSSelection>
<emrRTT name="RTT (nominal) - On Die Termination (ODT)">RZQ/6</emrRTT>
<emrPosted name="Additive Latency (AL)">0</emrPosted>
<emrOCD name="Write Leveling Enable">Disabled</emrOCD>
<emrDQS name="TDQS enable">Enabled</emrDQS>
<emrRDQS name="Qoff">Output Buffer Enabled</emrRDQS>
<mr2PartialArraySelfRefresh name="Partial-Array Self Refresh">Full Array</mr2PartialArraySelfRefresh>
<mr2CasWriteLatency name="CAS write latency">5</mr2CasWriteLatency>
<mr2AutoSelfRefresh name="Auto Self Refresh">Enabled</mr2AutoSelfRefresh>
<mr2SelfRefreshTempRange name="High Temparature Self Refresh Rate">Normal</mr2SelfRefreshTempRange>
<mr2RTTWR name="RTT_WR - Dynamic On Die Termination (ODT)">Dynamic ODT off</mr2RTTWR>
<PortInterface>NATIVE</PortInterface>
</Controller>
</Project>

View file

@ -0,0 +1,148 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Project NoOfControllers="1">
<!-- IMPORTANT: This is an internal file that has been generated by the MIG software. Any direct editing or changes made to this file may result in unpredictable behavior or data corruption. It is strongly advised that users do not edit the contents of this file. Re-run the MIG GUI with the required settings if any of the options provided below need to be altered. -->
<ModuleName>mig_dram_0</ModuleName>
<dci_inouts_inputs>1</dci_inouts_inputs>
<dci_inputs>1</dci_inputs>
<Debug_En>OFF</Debug_En>
<DataDepth_En>1024</DataDepth_En>
<LowPower_En>ON</LowPower_En>
<XADC_En>Enabled</XADC_En>
<TargetFPGA>xc7a35ti-csg324/-1L</TargetFPGA>
<Version>4.2</Version>
<SystemClock>No Buffer</SystemClock>
<ReferenceClock>No Buffer</ReferenceClock>
<SysResetPolarity>ACTIVE LOW</SysResetPolarity>
<BankSelectionFlag>FALSE</BankSelectionFlag>
<InternalVref>1</InternalVref>
<dci_hr_inouts_inputs>50 Ohms</dci_hr_inouts_inputs>
<dci_cascade>0</dci_cascade>
<Controller number="0">
<MemoryDevice>DDR3_SDRAM/Components/MT41K128M16XX-15E</MemoryDevice>
<TimePeriod>3000</TimePeriod>
<VccAuxIO>1.8V</VccAuxIO>
<PHYRatio>4:1</PHYRatio>
<InputClkFreq>83.333</InputClkFreq>
<UIExtraClocks>0</UIExtraClocks>
<MMCM_VCO>666</MMCM_VCO>
<MMCMClkOut0> 1.000</MMCMClkOut0>
<MMCMClkOut1>1</MMCMClkOut1>
<MMCMClkOut2>1</MMCMClkOut2>
<MMCMClkOut3>1</MMCMClkOut3>
<MMCMClkOut4>1</MMCMClkOut4>
<DataWidth>16</DataWidth>
<DeepMemory>1</DeepMemory>
<DataMask>1</DataMask>
<ECC>Disabled</ECC>
<Ordering>Strict</Ordering>
<BankMachineCnt>4</BankMachineCnt>
<CustomPart>FALSE</CustomPart>
<NewPartName/>
<RowAddress>14</RowAddress>
<ColAddress>10</ColAddress>
<BankAddress>3</BankAddress>
<MemoryVoltage>1.35V</MemoryVoltage>
<UserMemoryAddressMap>BANK_ROW_COLUMN</UserMemoryAddressMap>
<PinSelection>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="R2" SLEW="" VCCAUX_IO="" name="ddr3_addr[0]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="R6" SLEW="" VCCAUX_IO="" name="ddr3_addr[10]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="U6" SLEW="" VCCAUX_IO="" name="ddr3_addr[11]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="T6" SLEW="" VCCAUX_IO="" name="ddr3_addr[12]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="T8" SLEW="" VCCAUX_IO="" name="ddr3_addr[13]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="M6" SLEW="" VCCAUX_IO="" name="ddr3_addr[1]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="N4" SLEW="" VCCAUX_IO="" name="ddr3_addr[2]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="T1" SLEW="" VCCAUX_IO="" name="ddr3_addr[3]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="N6" SLEW="" VCCAUX_IO="" name="ddr3_addr[4]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="R7" SLEW="" VCCAUX_IO="" name="ddr3_addr[5]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="V6" SLEW="" VCCAUX_IO="" name="ddr3_addr[6]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="U7" SLEW="" VCCAUX_IO="" name="ddr3_addr[7]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="R8" SLEW="" VCCAUX_IO="" name="ddr3_addr[8]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="V7" SLEW="" VCCAUX_IO="" name="ddr3_addr[9]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="R1" SLEW="" VCCAUX_IO="" name="ddr3_ba[0]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="P4" SLEW="" VCCAUX_IO="" name="ddr3_ba[1]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="P2" SLEW="" VCCAUX_IO="" name="ddr3_ba[2]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="M4" SLEW="" VCCAUX_IO="" name="ddr3_cas_n"/>
<Pin IN_TERM="" IOSTANDARD="DIFF_SSTL135" PADName="V9" SLEW="" VCCAUX_IO="" name="ddr3_ck_n[0]"/>
<Pin IN_TERM="" IOSTANDARD="DIFF_SSTL135" PADName="U9" SLEW="" VCCAUX_IO="" name="ddr3_ck_p[0]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="N5" SLEW="" VCCAUX_IO="" name="ddr3_cke[0]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="U8" SLEW="" VCCAUX_IO="" name="ddr3_cs_n[0]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="L1" SLEW="" VCCAUX_IO="" name="ddr3_dm[0]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="U1" SLEW="" VCCAUX_IO="" name="ddr3_dm[1]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="K5" SLEW="" VCCAUX_IO="" name="ddr3_dq[0]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="U4" SLEW="" VCCAUX_IO="" name="ddr3_dq[10]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="V5" SLEW="" VCCAUX_IO="" name="ddr3_dq[11]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="V1" SLEW="" VCCAUX_IO="" name="ddr3_dq[12]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="T3" SLEW="" VCCAUX_IO="" name="ddr3_dq[13]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="U3" SLEW="" VCCAUX_IO="" name="ddr3_dq[14]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="R3" SLEW="" VCCAUX_IO="" name="ddr3_dq[15]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="L3" SLEW="" VCCAUX_IO="" name="ddr3_dq[1]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="K3" SLEW="" VCCAUX_IO="" name="ddr3_dq[2]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="L6" SLEW="" VCCAUX_IO="" name="ddr3_dq[3]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="M3" SLEW="" VCCAUX_IO="" name="ddr3_dq[4]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="M1" SLEW="" VCCAUX_IO="" name="ddr3_dq[5]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="L4" SLEW="" VCCAUX_IO="" name="ddr3_dq[6]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="M2" SLEW="" VCCAUX_IO="" name="ddr3_dq[7]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="V4" SLEW="" VCCAUX_IO="" name="ddr3_dq[8]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="T5" SLEW="" VCCAUX_IO="" name="ddr3_dq[9]"/>
<Pin IN_TERM="" IOSTANDARD="DIFF_SSTL135" PADName="N1" SLEW="" VCCAUX_IO="" name="ddr3_dqs_n[0]"/>
<Pin IN_TERM="" IOSTANDARD="DIFF_SSTL135" PADName="V2" SLEW="" VCCAUX_IO="" name="ddr3_dqs_n[1]"/>
<Pin IN_TERM="" IOSTANDARD="DIFF_SSTL135" PADName="N2" SLEW="" VCCAUX_IO="" name="ddr3_dqs_p[0]"/>
<Pin IN_TERM="" IOSTANDARD="DIFF_SSTL135" PADName="U2" SLEW="" VCCAUX_IO="" name="ddr3_dqs_p[1]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="R5" SLEW="" VCCAUX_IO="" name="ddr3_odt[0]"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="P3" SLEW="" VCCAUX_IO="" name="ddr3_ras_n"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="K6" SLEW="" VCCAUX_IO="" name="ddr3_reset_n"/>
<Pin IN_TERM="" IOSTANDARD="SSTL135" PADName="P5" SLEW="" VCCAUX_IO="" name="ddr3_we_n"/>
</PinSelection>
<System_Control>
<Pin Bank="Select Bank" PADName="No connect" name="sys_rst"/>
<Pin Bank="Select Bank" PADName="No connect" name="init_calib_complete"/>
<Pin Bank="Select Bank" PADName="No connect" name="tg_compare_error"/>
</System_Control>
<TimingParameters>
<Parameters tcke="5.625" tfaw="45" tras="36" trcd="13.5" trefi="7.8" trfc="160" trp="13.5" trrd="7.5" trtp="7.5" twtr="7.5"/>
</TimingParameters>
<mrBurstLength name="Burst Length">8 - Fixed</mrBurstLength>
<mrBurstType name="Read Burst Type and Length">Sequential</mrBurstType>
<mrCasLatency name="CAS Latency">5</mrCasLatency>
<mrMode name="Mode">Normal</mrMode>
<mrDllReset name="DLL Reset">No</mrDllReset>
<mrPdMode name="DLL control for precharge PD">Slow Exit</mrPdMode>
<emrDllEnable name="DLL Enable">Enable</emrDllEnable>
<emrOutputDriveStrength name="Output Driver Impedance Control">RZQ/6</emrOutputDriveStrength>
<emrMirrorSelection name="Address Mirroring">Disable</emrMirrorSelection>
<emrCSSelection name="Controller Chip Select Pin">Enable</emrCSSelection>
<emrRTT name="RTT (nominal) - On Die Termination (ODT)">RZQ/6</emrRTT>
<emrPosted name="Additive Latency (AL)">0</emrPosted>
<emrOCD name="Write Leveling Enable">Disabled</emrOCD>
<emrDQS name="TDQS enable">Enabled</emrDQS>
<emrRDQS name="Qoff">Output Buffer Enabled</emrRDQS>
<mr2PartialArraySelfRefresh name="Partial-Array Self Refresh">Full Array</mr2PartialArraySelfRefresh>
<mr2CasWriteLatency name="CAS write latency">5</mr2CasWriteLatency>
<mr2AutoSelfRefresh name="Auto Self Refresh">Enabled</mr2AutoSelfRefresh>
<mr2SelfRefreshTempRange name="High Temparature Self Refresh Rate">Normal</mr2SelfRefreshTempRange>
<mr2RTTWR name="RTT_WR - Dynamic On Die Termination (ODT)">Dynamic ODT off</mr2RTTWR>
<PortInterface>NATIVE</PortInterface>
</Controller>
</Project>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,176 @@
<?xml version="1.0" encoding="UTF-8"?>
<wave_config>
<wave_state>
</wave_state>
<db_ref_list>
<db_ref path="sdspi_testbench_behav.wdb" id="1">
<top_modules>
<top_module name="glbl" />
<top_module name="sdspi_testbench" />
</top_modules>
</db_ref>
</db_ref_list>
<zoom_setting>
<ZoomStartTime time="35023635fs"></ZoomStartTime>
<ZoomEndTime time="36066046fs"></ZoomEndTime>
<Cursor1Time time="32155000fs"></Cursor1Time>
</zoom_setting>
<column_width_setting>
<NameColumnWidth column_width="149"></NameColumnWidth>
<ValueColumnWidth column_width="90"></ValueColumnWidth>
</column_width_setting>
<WVObjectSize size="35" />
<wave_markers>
<marker time="30925000" label="" />
</wave_markers>
<wvobject fp_name="/sdspi_testbench/clk" type="logic">
<obj_property name="ElementShortName">clk</obj_property>
<obj_property name="ObjectShortName">clk</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/tx_data" type="array">
<obj_property name="ElementShortName">tx_data[7:0]</obj_property>
<obj_property name="ObjectShortName">tx_data[7:0]</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/rx_data" type="array">
<obj_property name="ElementShortName">rx_data[7:0]</obj_property>
<obj_property name="ObjectShortName">rx_data[7:0]</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/UUT/rx_shifter" type="array">
<obj_property name="ElementShortName">rx_shifter[7:0]</obj_property>
<obj_property name="ObjectShortName">rx_shifter[7:0]</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/UUT/tx_shifter" type="array">
<obj_property name="ElementShortName">tx_shifter[7:0]</obj_property>
<obj_property name="ObjectShortName">tx_shifter[7:0]</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/UUT/tx_fifo_out" type="array">
<obj_property name="ElementShortName">tx_fifo_out[7:0]</obj_property>
<obj_property name="ObjectShortName">tx_fifo_out[7:0]</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/UUT/tx_fifo_rd_en" type="logic">
<obj_property name="ElementShortName">tx_fifo_rd_en</obj_property>
<obj_property name="ObjectShortName">tx_fifo_rd_en</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/UUT/tx_fifo_wr_en" type="logic">
<obj_property name="ElementShortName">tx_fifo_wr_en</obj_property>
<obj_property name="ObjectShortName">tx_fifo_wr_en</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/UUT/rx_fifo_wr_en" type="logic">
<obj_property name="ElementShortName">rx_fifo_wr_en</obj_property>
<obj_property name="ObjectShortName">rx_fifo_wr_en</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/UUT/rx_bit_recvd" type="logic">
<obj_property name="ElementShortName">rx_bit_recvd</obj_property>
<obj_property name="ObjectShortName">rx_bit_recvd</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/UUT/tx_fifo/tail_x" type="array">
<obj_property name="ElementShortName">tail_x[4:0]</obj_property>
<obj_property name="ObjectShortName">tail_x[4:0]</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/UUT/tx_fifo/head_x" type="array">
<obj_property name="ElementShortName">head_x[4:0]</obj_property>
<obj_property name="ObjectShortName">head_x[4:0]</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/tx_ready" type="logic">
<obj_property name="ElementShortName">tx_ready</obj_property>
<obj_property name="ObjectShortName">tx_ready</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/tx_empty" type="logic">
<obj_property name="ElementShortName">tx_empty</obj_property>
<obj_property name="ObjectShortName">tx_empty</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/rx_avail" type="logic">
<obj_property name="ElementShortName">rx_avail</obj_property>
<obj_property name="ObjectShortName">rx_avail</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/tx_write" type="logic">
<obj_property name="ElementShortName">tx_write</obj_property>
<obj_property name="ObjectShortName">tx_write</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/rx_read" type="logic">
<obj_property name="ElementShortName">rx_read</obj_property>
<obj_property name="ObjectShortName">rx_read</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/ctrl_write" type="logic">
<obj_property name="ElementShortName">ctrl_write</obj_property>
<obj_property name="ObjectShortName">ctrl_write</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/rx_filter_en" type="logic">
<obj_property name="ElementShortName">rx_filter_en</obj_property>
<obj_property name="ObjectShortName">rx_filter_en</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/txrx_en" type="logic">
<obj_property name="ElementShortName">txrx_en</obj_property>
<obj_property name="ObjectShortName">txrx_en</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/spiclk_div_wr" type="logic">
<obj_property name="ElementShortName">spiclk_div_wr</obj_property>
<obj_property name="ObjectShortName">spiclk_div_wr</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/UUT/spi_clk_on" type="logic">
<obj_property name="ElementShortName">spi_clk_on</obj_property>
<obj_property name="ObjectShortName">spi_clk_on</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/spiclk_f_en" type="logic">
<obj_property name="ElementShortName">spiclk_f_en</obj_property>
<obj_property name="ObjectShortName">spiclk_f_en</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/UUT/spi_clk_f_on" type="logic">
<obj_property name="ElementShortName">spi_clk_f_on</obj_property>
<obj_property name="ObjectShortName">spi_clk_f_on</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/sd_cs_n" type="logic">
<obj_property name="ElementShortName">sd_cs_n</obj_property>
<obj_property name="ObjectShortName">sd_cs_n</obj_property>
<obj_property name="CustomSignalColor">#DCDCDC</obj_property>
<obj_property name="UseCustomSignalColor">true</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/sd_mosi" type="logic">
<obj_property name="ElementShortName">sd_mosi</obj_property>
<obj_property name="ObjectShortName">sd_mosi</obj_property>
<obj_property name="CustomSignalColor">#00FFFF</obj_property>
<obj_property name="UseCustomSignalColor">true</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/sd_miso" type="logic">
<obj_property name="ElementShortName">sd_miso</obj_property>
<obj_property name="ObjectShortName">sd_miso</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/sd_sck" type="logic">
<obj_property name="ElementShortName">sd_sck</obj_property>
<obj_property name="ObjectShortName">sd_sck</obj_property>
<obj_property name="CustomSignalColor">#FFFF00</obj_property>
<obj_property name="UseCustomSignalColor">true</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/UUT/xcvr_on" type="logic">
<obj_property name="ElementShortName">xcvr_on</obj_property>
<obj_property name="ObjectShortName">xcvr_on</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/UUT/hphase_start" type="logic">
<obj_property name="ElementShortName">hphase_start</obj_property>
<obj_property name="ObjectShortName">hphase_start</obj_property>
<obj_property name="CustomSignalColor">#F0E68C</obj_property>
<obj_property name="UseCustomSignalColor">true</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/UUT/clk_phase" type="array">
<obj_property name="ElementShortName">clk_phase[1:0]</obj_property>
<obj_property name="ObjectShortName">clk_phase[1:0]</obj_property>
<obj_property name="CustomSignalColor">#D2691E</obj_property>
<obj_property name="UseCustomSignalColor">true</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/UUT/running" type="logic">
<obj_property name="ElementShortName">running</obj_property>
<obj_property name="ObjectShortName">running</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/UUT/xcvr_bitcount" type="array">
<obj_property name="ElementShortName">xcvr_bitcount[3:0]</obj_property>
<obj_property name="ObjectShortName">xcvr_bitcount[3:0]</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/UUT/spi_clk_count" type="array">
<obj_property name="ElementShortName">spi_clk_count[6:0]</obj_property>
<obj_property name="ObjectShortName">spi_clk_count[6:0]</obj_property>
</wvobject>
<wvobject fp_name="/sdspi_testbench/UUT/spi_clk_div" type="array">
<obj_property name="ElementShortName">spi_clk_div[6:0]</obj_property>
<obj_property name="ObjectShortName">spi_clk_div[6:0]</obj_property>
</wvobject>
</wave_config>

View file

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<wave_config>
<wave_state>
</wave_state>
<db_ref_list>
<db_ref path="testbench_behav.wdb" id="1">
<top_modules>
<top_module name="glbl" />
<top_module name="testbench" />
</top_modules>
</db_ref>
</db_ref_list>
<zoom_setting>
<ZoomStartTime time="3880386400fs"></ZoomStartTime>
<ZoomEndTime time="4023922720fs"></ZoomEndTime>
<Cursor1Time time="4000000000fs"></Cursor1Time>
</zoom_setting>
<column_width_setting>
<NameColumnWidth column_width="209"></NameColumnWidth>
<ValueColumnWidth column_width="90"></ValueColumnWidth>
</column_width_setting>
<WVObjectSize size="16" />
<wvobject fp_name="/testbench/clk" type="logic">
<obj_property name="ElementShortName">clk</obj_property>
<obj_property name="ObjectShortName">clk</obj_property>
</wvobject>
<wvobject fp_name="/testbench/top0/cpu0/addr" type="array">
<obj_property name="ElementShortName">addr[31:0]</obj_property>
<obj_property name="ObjectShortName">addr[31:0]</obj_property>
</wvobject>
<wvobject fp_name="/testbench/top0/cpu0/data_in" type="array">
<obj_property name="ElementShortName">data_in[31:0]</obj_property>
<obj_property name="ObjectShortName">data_in[31:0]</obj_property>
</wvobject>
<wvobject fp_name="/testbench/top0/cpu0/data_out" type="array">
<obj_property name="ElementShortName">data_out[31:0]</obj_property>
<obj_property name="ObjectShortName">data_out[31:0]</obj_property>
</wvobject>
<wvobject fp_name="/testbench/top0/cpu0/seq_state" type="array">
<obj_property name="ElementShortName">seq_state[1:0]</obj_property>
<obj_property name="ObjectShortName">seq_state[1:0]</obj_property>
</wvobject>
<wvobject fp_name="/testbench/top0/cpu0/PC" type="array">
<obj_property name="ElementShortName">PC[31:0]</obj_property>
<obj_property name="ObjectShortName">PC[31:0]</obj_property>
</wvobject>
<wvobject fp_name="/testbench/top0/cpu0/nPC" type="array">
<obj_property name="ElementShortName">nPC[31:0]</obj_property>
<obj_property name="ObjectShortName">nPC[31:0]</obj_property>
</wvobject>
<wvobject fp_name="/testbench/top0/cpu0/ins" type="array">
<obj_property name="ElementShortName">ins[15:0]</obj_property>
<obj_property name="ObjectShortName">ins[15:0]</obj_property>
<obj_property name="Radix">BINARYRADIX</obj_property>
</wvobject>
<wvobject fp_name="/testbench/top0/cpu0/ins_branch" type="logic">
<obj_property name="ElementShortName">ins_branch</obj_property>
<obj_property name="ObjectShortName">ins_branch</obj_property>
</wvobject>
<wvobject fp_name="/testbench/top0/cpu0/ins_loadrel" type="logic">
<obj_property name="ElementShortName">ins_loadrel</obj_property>
<obj_property name="ObjectShortName">ins_loadrel</obj_property>
</wvobject>
<wvobject fp_name="/testbench/top0/cpu0/X" type="array">
<obj_property name="ElementShortName">X[31:0]</obj_property>
<obj_property name="ObjectShortName">X[31:0]</obj_property>
</wvobject>
<wvobject fp_name="/testbench/top0/cpu0/nX" type="array">
<obj_property name="ElementShortName">nX[31:0]</obj_property>
<obj_property name="ObjectShortName">nX[31:0]</obj_property>
</wvobject>
<wvobject fp_name="/testbench/top0/cpu0/FP" type="array">
<obj_property name="ElementShortName">FP[31:0]</obj_property>
<obj_property name="ObjectShortName">FP[31:0]</obj_property>
</wvobject>
<wvobject fp_name="/testbench/top0/cpu0/pc_next_ins" type="array">
<obj_property name="ElementShortName">pc_next_ins[31:0]</obj_property>
<obj_property name="ObjectShortName">pc_next_ins[31:0]</obj_property>
</wvobject>
<wvobject fp_name="/testbench/top0/cpu0/mem_wait" type="logic">
<obj_property name="ElementShortName">mem_wait</obj_property>
<obj_property name="ObjectShortName">mem_wait</obj_property>
</wvobject>
<wvobject fp_name="/testbench/top0/cpu0/ins_buf" type="array">
<obj_property name="ElementShortName">ins_buf[15:0]</obj_property>
<obj_property name="ObjectShortName">ins_buf[15:0]</obj_property>
</wvobject>
</wave_config>

724
rtl/arty-a7/tridoracpu.tcl Normal file
View file

@ -0,0 +1,724 @@
#*****************************************************************************************
# Vivado (TM) v2020.1 (64-bit)
#
# tridoracpu.tcl: Tcl script for re-creating project 'tridoracpu'
#
# Generated by Vivado on Sat Sep 14 23:58:12 +0200 2024
# IP Build 2902112 on Wed May 27 22:43:36 MDT 2020
#
# This file contains the Vivado Tcl commands for re-creating the project to the state*
# when this script was generated. In order to re-create the project, please source this
# file in the Vivado Tcl Shell.
#
# * Note that the runs in the created project will be configured the same way as the
# original project, however they will not be launched automatically. To regenerate the
# run results please launch the synthesis/implementation runs as needed.
#
#*****************************************************************************************
# NOTE: In order to use this script for source control purposes, please make sure that the
# following files are added to the source control system:-
#
# 1. This project restoration tcl script (tridoracpu.tcl) that was generated.
#
# 2. The following source(s) files that were local or imported into the original project.
# (Please see the '$orig_proj_dir' and '$origin_dir' variable setting below at the start of the script)
#
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/cpuclk.v"
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/display_clock.v"
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/mem.v"
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/stack.v"
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/stackcpu.v"
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/vgafb.v"
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/top.v"
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/testbench.v"
# "C:/Users/sebastian/develop/fpga/tridoracpu/rom.mem"
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/ip/mig_dram_0/mig_a.prj"
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/ip/mig_dram_0/mig_b.prj"
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/dram_bridge.v"
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/sdspi.v"
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/bram_tdp.v"
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/palette.v"
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/irqctrl.v"
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/fifo.v"
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/fifo_testbench.v"
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/sdspi_testbench.v"
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/ip/mig_dram_0/mig_dram_0.xci"
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sim_1/new/uart_tb.v"
# "C:/Users/sebastian/develop/fpga/tridoracpu/testbench_behav1.wcfg"
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/fifo.v"
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/fifo_testbench.v"
# "C:/Users/sebastian/develop/fpga/tridoracpu/sdspi_testbench_behav.wcfg"
#
# 3. The following remote source files that were added to the original project:-
#
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/imports/verilog/uart.v"
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/constrs_1/imports/fpga/Arty-A7-35-Master.xdc"
#
#*****************************************************************************************
#xhub::refresh_catalog [xhub::get_xstores xilinx_board_store]
# this will take quite some time
#xhub::install [xhub::get_xitems]
# Set the reference directory for source file relative paths (by default the value is script directory path)
set origin_dir "C:/Users/sebastian/develop/Tridora/rtl"
# Oh come on, Xilinx, why?
#set xilinx_board_store_dir "../../../../AppData/Roaming/Xilinx/Vivado/2020.1/xhub/board_store/xilinx_board_store"
set xilinx_board_store_dir [get_property LOCAL_ROOT_DIR [xhub::get_xstores xilinx_board_store]]
set_param board.repoPaths [get_property LOCAL_ROOT_DIR [xhub::get_xstores xilinx_board_store]]
# Use origin directory path location variable, if specified in the tcl shell
if { [info exists ::origin_dir_loc] } {
set origin_dir $::origin_dir_loc
}
# Set the project name
set _xil_proj_name_ "tridoracpu"
# Use project name variable, if specified in the tcl shell
if { [info exists ::user_project_name] } {
set _xil_proj_name_ $::user_project_name
}
variable script_file
set script_file "tridoracpu.tcl"
# Help information for this script
proc print_help {} {
variable script_file
puts "\nDescription:"
puts "Recreate a Vivado project from this script. The created project will be"
puts "functionally equivalent to the original project for which this script was"
puts "generated. The script contains commands for creating a project, filesets,"
puts "runs, adding/importing sources and setting properties on various objects.\n"
puts "Syntax:"
puts "$script_file"
puts "$script_file -tclargs \[--origin_dir <path>\]"
puts "$script_file -tclargs \[--project_name <name>\]"
puts "$script_file -tclargs \[--help\]\n"
puts "Usage:"
puts "Name Description"
puts "-------------------------------------------------------------------------"
puts "\[--origin_dir <path>\] Determine source file paths wrt this path. Default"
puts " origin_dir path value is \".\", otherwise, the value"
puts " that was set with the \"-paths_relative_to\" switch"
puts " when this script was generated.\n"
puts "\[--project_name <name>\] Create project with the specified name. Default"
puts " name is the name of the project from where this"
puts " script was generated.\n"
puts "\[--help\] Print help information for this script"
puts "-------------------------------------------------------------------------\n"
exit 0
}
if { $::argc > 0 } {
for {set i 0} {$i < $::argc} {incr i} {
set option [string trim [lindex $::argv $i]]
switch -regexp -- $option {
"--origin_dir" { incr i; set origin_dir [lindex $::argv $i] }
"--project_name" { incr i; set _xil_proj_name_ [lindex $::argv $i] }
"--help" { print_help }
default {
if { [regexp {^-} $option] } {
puts "ERROR: Unknown option '$option' specified, please type '$script_file -tclargs --help' for usage info.\n"
return 1
}
}
}
}
}
# Set the directory path for the original project from where this script was exported
set orig_proj_dir "[file normalize "${origin_dir}/arty-a7"]"
# Create project
create_project ${_xil_proj_name_} ./${_xil_proj_name_} -part xc7a35ticsg324-1L
# Set the directory path for the new project
set proj_dir [get_property directory [current_project]]
# Set project properties
set obj [current_project]
#set_property -name "board_part_repo_paths" -value "[file normalize "$xilinx_board_store_dir"]" -objects $obj
set_property -name "board_part" -value "digilentinc.com:arty-a7-35:part0:1.0" -objects $obj
set_property -name "default_lib" -value "xil_defaultlib" -objects $obj
set_property -name "enable_vhdl_2008" -value "1" -objects $obj
set_property -name "ip_cache_permissions" -value "read write" -objects $obj
set_property -name "ip_output_repo" -value "$proj_dir/${_xil_proj_name_}.cache/ip" -objects $obj
set_property -name "mem.enable_memory_map_generation" -value "1" -objects $obj
set_property -name "platform.board_id" -value "arty-a7-35" -objects $obj
set_property -name "sim.central_dir" -value "$proj_dir/${_xil_proj_name_}.ip_user_files" -objects $obj
set_property -name "sim.ip.auto_export_scripts" -value "1" -objects $obj
set_property -name "simulator_language" -value "Mixed" -objects $obj
set_property -name "source_mgmt_mode" -value "DisplayOnly" -objects $obj
set_property -name "webtalk.activehdl_export_sim" -value "4" -objects $obj
set_property -name "webtalk.ies_export_sim" -value "4" -objects $obj
set_property -name "webtalk.modelsim_export_sim" -value "4" -objects $obj
set_property -name "webtalk.questa_export_sim" -value "4" -objects $obj
set_property -name "webtalk.riviera_export_sim" -value "4" -objects $obj
set_property -name "webtalk.vcs_export_sim" -value "4" -objects $obj
set_property -name "webtalk.xsim_export_sim" -value "4" -objects $obj
set_property -name "webtalk.xsim_launch_sim" -value "537" -objects $obj
# Create 'sources_1' fileset (if not found)
if {[string equal [get_filesets -quiet sources_1] ""]} {
create_fileset -srcset sources_1
}
# Set 'sources_1' fileset object
set obj [get_filesets sources_1]
set files [list \
[file normalize "${origin_dir}/src/uart.v"] \
]
add_files -norecurse -fileset $obj $files
# Add local files from the original project (-no_copy_sources specified)
set files [list \
[file normalize "${origin_dir}/src/cpuclk.v" ]\
[file normalize "${origin_dir}/src/display_clock.v" ]\
[file normalize "${origin_dir}/src/mem.v" ]\
[file normalize "${origin_dir}/src/stack.v" ]\
[file normalize "${origin_dir}/src/stackcpu.v" ]\
[file normalize "${origin_dir}/src/vgafb.v" ]\
[file normalize "${origin_dir}/src/top.v" ]\
[file normalize "${origin_dir}/src/testbench.v" ]\
[file normalize "${orig_proj_dir}/rom.mem" ]\
[file normalize "${orig_proj_dir}/mig_dram_0/mig_a.prj" ]\
[file normalize "${orig_proj_dir}/mig_dram_0/mig_b.prj" ]\
[file normalize "${origin_dir}/src/dram_bridge.v" ]\
[file normalize "${origin_dir}/src/sdspi.v" ]\
[file normalize "${origin_dir}/src/bram_tdp.v" ]\
[file normalize "${origin_dir}/src/palette.v" ]\
[file normalize "${origin_dir}/src/irqctrl.v" ]\
[file normalize "${origin_dir}/src/fifo.v" ]\
[file normalize "${origin_dir}/src/fifo_testbench.v" ]\
[file normalize "${origin_dir}/src/sdspi_testbench.v" ]\
]
set added_files [add_files -fileset sources_1 $files]
# Set 'sources_1' fileset file properties for remote files
set file "$origin_dir/src/uart.v"
set file [file normalize $file]
set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
set_property -name "used_in" -value "synthesis implementation" -objects $file_obj
set_property -name "used_in_simulation" -value "0" -objects $file_obj
# Set 'sources_1' fileset file properties for local files
set file "src/cpuclk.v"
set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
set_property -name "used_in" -value "synthesis implementation" -objects $file_obj
set_property -name "used_in_simulation" -value "0" -objects $file_obj
set file "src/display_clock.v"
set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
set_property -name "is_enabled" -value "0" -objects $file_obj
set file "src/mem.v"
set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
set_property -name "used_in" -value "synthesis implementation" -objects $file_obj
set_property -name "used_in_simulation" -value "0" -objects $file_obj
set file "src/stack.v"
set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
set_property -name "used_in" -value "synthesis implementation" -objects $file_obj
set_property -name "used_in_simulation" -value "0" -objects $file_obj
set file "src/stackcpu.v"
set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
set_property -name "used_in" -value "synthesis implementation" -objects $file_obj
set_property -name "used_in_simulation" -value "0" -objects $file_obj
set file "src/vgafb.v"
set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
set_property -name "used_in" -value "synthesis implementation" -objects $file_obj
set_property -name "used_in_simulation" -value "0" -objects $file_obj
set file "src/top.v"
set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
set_property -name "used_in" -value "synthesis implementation" -objects $file_obj
set_property -name "used_in_simulation" -value "0" -objects $file_obj
set file "src/testbench.v"
set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
set_property -name "used_in" -value "" -objects $file_obj
set_property -name "used_in_implementation" -value "0" -objects $file_obj
set_property -name "used_in_simulation" -value "0" -objects $file_obj
set_property -name "used_in_synthesis" -value "0" -objects $file_obj
set file "arty-a7/rom.mem"
set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
set_property -name "file_type" -value "Memory File" -objects $file_obj
set file "arty-a7/mig_dram_0/mig_a.prj"
set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
set_property -name "scoped_to_cells" -value "mig_dram_0" -objects $file_obj
set file "arty-a7/mig_dram_0/mig_b.prj"
set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
set_property -name "scoped_to_cells" -value "mig_dram_0" -objects $file_obj
set file "src/dram_bridge.v"
set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
set_property -name "used_in" -value "synthesis implementation" -objects $file_obj
set_property -name "used_in_simulation" -value "0" -objects $file_obj
set file "src/palette.v"
set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
set_property -name "used_in" -value "synthesis implementation" -objects $file_obj
set_property -name "used_in_simulation" -value "0" -objects $file_obj
set file "src/irqctrl.v"
set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
set_property -name "used_in" -value "synthesis implementation" -objects $file_obj
set_property -name "used_in_simulation" -value "0" -objects $file_obj
set file "src/fifo_testbench.v"
set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
set_property -name "used_in" -value "" -objects $file_obj
set_property -name "used_in_implementation" -value "0" -objects $file_obj
set_property -name "used_in_simulation" -value "0" -objects $file_obj
set_property -name "used_in_synthesis" -value "0" -objects $file_obj
# Set 'sources_1' fileset properties
set obj [get_filesets sources_1]
set_property -name "top" -value "top" -objects $obj
set_property -name "top_auto_set" -value "0" -objects $obj
# Set 'sources_1' fileset object
set obj [get_filesets sources_1]
# Add local files from the original project (-no_copy_sources specified)
set files [list \
[file normalize "${orig_proj_dir}/mig_dram_0/mig_dram_0.xci" ]\
]
set added_files [add_files -fileset sources_1 $files]
# Set 'sources_1' fileset file properties for remote files
# None
# Set 'sources_1' fileset file properties for local files
set file "arty-a7/mig_dram_0/mig_dram_0.xci"
set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
set_property -name "generate_files_for_reference" -value "0" -objects $file_obj
set_property -name "registered_with_manager" -value "1" -objects $file_obj
if { ![get_property "is_locked" $file_obj] } {
set_property -name "synth_checkpoint_mode" -value "Singular" -objects $file_obj
}
set_property -name "used_in" -value "synthesis implementation" -objects $file_obj
set_property -name "used_in_simulation" -value "0" -objects $file_obj
# Create 'constrs_1' fileset (if not found)
if {[string equal [get_filesets -quiet constrs_1] ""]} {
create_fileset -constrset constrs_1
}
# Set 'constrs_1' fileset object
set obj [get_filesets constrs_1]
# Add/Import constrs file and set constrs file properties
set file "[file normalize ${origin_dir}/arty-a7/Arty-A7-35-Master.xdc]"
set file_added [add_files -norecurse -fileset $obj [list $file]]
set file "$origin_dir/arty-a7/Arty-A7-35-Master.xdc"
set file [file normalize $file]
set file_obj [get_files -of_objects [get_filesets constrs_1] [list "*$file"]]
set_property -name "file_type" -value "XDC" -objects $file_obj
# Set 'constrs_1' fileset properties
set obj [get_filesets constrs_1]
set_property -name "target_constrs_file" -value "$orig_proj_dir/Arty-A7-35-Master.xdc" -objects $obj
set_property -name "target_ucf" -value "$orig_proj_dir/Arty-A7-35-Master.xdc" -objects $obj
# Create 'sim_1' fileset (if not found)
if {[string equal [get_filesets -quiet sim_1] ""]} {
create_fileset -simset sim_1
}
# Set 'sim_1' fileset object
set obj [get_filesets sim_1]
# Add local files from the original project (-no_copy_sources specified)
set files [list \
[file normalize "${origin_dir}/src/uart_tb.v" ]\
[file normalize "${orig_proj_dir}/testbench_behav1.wcfg" ]\
]
set added_files [add_files -fileset sim_1 $files]
# Set 'sim_1' fileset file properties for remote files
# None
# Set 'sim_1' fileset file properties for local files
set file [file normalize "${origin_dir}/src/uart_tb.v"]
set file_obj [get_files -of_objects [get_filesets sim_1] [list "*$file"]]
set_property -name "used_in" -value "" -objects $file_obj
set_property -name "used_in_implementation" -value "0" -objects $file_obj
set_property -name "used_in_simulation" -value "0" -objects $file_obj
set_property -name "used_in_synthesis" -value "0" -objects $file_obj
# Set 'sim_1' fileset properties
set obj [get_filesets sim_1]
set_property -name "hbs.configure_design_for_hier_access" -value "1" -objects $obj
set_property -name "nl.mode" -value "funcsim" -objects $obj
set_property -name "top" -value "testbench" -objects $obj
set_property -name "top_lib" -value "xil_defaultlib" -objects $obj
# Create 'sim_fifo' fileset (if not found)
if {[string equal [get_filesets -quiet sim_fifo] ""]} {
create_fileset -simset sim_fifo
}
# Set 'sim_fifo' fileset object
set obj [get_filesets sim_fifo]
# Add local files from the original project (-no_copy_sources specified)
set files [list \
[file normalize "${origin_dir}/src/fifo.v" ]\
[file normalize "${origin_dir}/src/fifo_testbench.v" ]\
]
set added_files [add_files -fileset sim_fifo $files]
# Set 'sim_fifo' fileset file properties for remote files
# None
# Set 'sim_fifo' fileset file properties for local files
# None
# Set 'sim_fifo' fileset properties
set obj [get_filesets sim_fifo]
set_property -name "hbs.configure_design_for_hier_access" -value "1" -objects $obj
set_property -name "top" -value "fifo_testbench" -objects $obj
set_property -name "top_auto_set" -value "0" -objects $obj
# Create 'sim_sdspi' fileset (if not found)
if {[string equal [get_filesets -quiet sim_sdspi] ""]} {
create_fileset -simset sim_sdspi
}
# Set 'sim_sdspi' fileset object
set obj [get_filesets sim_sdspi]
# Add local files from the original project (-no_copy_sources specified)
set files [list \
[file normalize "${orig_proj_dir}/sdspi_testbench_behav.wcfg" ]\
]
set added_files [add_files -fileset sim_sdspi $files]
# Set 'sim_sdspi' fileset file properties for remote files
# None
# Set 'sim_sdspi' fileset file properties for local files
# None
# Set 'sim_sdspi' fileset properties
set obj [get_filesets sim_sdspi]
set_property -name "hbs.configure_design_for_hier_access" -value "1" -objects $obj
set_property -name "sim_mode" -value "post-synthesis" -objects $obj
set_property -name "top" -value "sdspi_testbench" -objects $obj
set_property -name "top_auto_set" -value "0" -objects $obj
set_property -name "top_lib" -value "xil_defaultlib" -objects $obj
set_property -name "xsim.simulate.runtime" -value "10ms" -objects $obj
# Set 'utils_1' fileset object
set obj [get_filesets utils_1]
# Empty (no sources present)
# Set 'utils_1' fileset properties
set obj [get_filesets utils_1]
# Create 'synth_1' run (if not found)
if {[string equal [get_runs -quiet synth_1] ""]} {
create_run -name synth_1 -part xc7a35ticsg324-1L -flow {Vivado Synthesis 2020} -strategy "Vivado Synthesis Defaults" -report_strategy {No Reports} -constrset constrs_1
} else {
set_property strategy "Vivado Synthesis Defaults" [get_runs synth_1]
set_property flow "Vivado Synthesis 2020" [get_runs synth_1]
}
set obj [get_runs synth_1]
set_property set_report_strategy_name 1 $obj
set_property report_strategy {Vivado Synthesis Default Reports} $obj
set_property set_report_strategy_name 0 $obj
# Create 'synth_1_synth_report_utilization_0' report (if not found)
if { [ string equal [get_report_configs -of_objects [get_runs synth_1] synth_1_synth_report_utilization_0] "" ] } {
create_report_config -report_name synth_1_synth_report_utilization_0 -report_type report_utilization:1.0 -steps synth_design -runs synth_1
}
set obj [get_report_configs -of_objects [get_runs synth_1] synth_1_synth_report_utilization_0]
if { $obj != "" } {
}
set obj [get_runs synth_1]
set_property -name "needs_refresh" -value "1" -objects $obj
set_property -name "strategy" -value "Vivado Synthesis Defaults" -objects $obj
# set the current synth run
current_run -synthesis [get_runs synth_1]
# Create 'impl_1' run (if not found)
if {[string equal [get_runs -quiet impl_1] ""]} {
create_run -name impl_1 -part xc7a35ticsg324-1L -flow {Vivado Implementation 2020} -strategy "Performance_RefinePlacement" -report_strategy {No Reports} -constrset constrs_1 -parent_run synth_1
} else {
set_property strategy "Performance_RefinePlacement" [get_runs impl_1]
set_property flow "Vivado Implementation 2020" [get_runs impl_1]
}
set obj [get_runs impl_1]
set_property set_report_strategy_name 1 $obj
set_property report_strategy {Vivado Implementation Default Reports} $obj
set_property set_report_strategy_name 0 $obj
# Create 'impl_1_init_report_timing_summary_0' report (if not found)
if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_init_report_timing_summary_0] "" ] } {
create_report_config -report_name impl_1_init_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps init_design -runs impl_1
}
set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_init_report_timing_summary_0]
if { $obj != "" } {
set_property -name "is_enabled" -value "0" -objects $obj
set_property -name "options.max_paths" -value "10" -objects $obj
}
# Create 'impl_1_opt_report_drc_0' report (if not found)
if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_drc_0] "" ] } {
create_report_config -report_name impl_1_opt_report_drc_0 -report_type report_drc:1.0 -steps opt_design -runs impl_1
}
set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_drc_0]
if { $obj != "" } {
}
# Create 'impl_1_opt_report_timing_summary_0' report (if not found)
if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_timing_summary_0] "" ] } {
create_report_config -report_name impl_1_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps opt_design -runs impl_1
}
set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_timing_summary_0]
if { $obj != "" } {
set_property -name "is_enabled" -value "0" -objects $obj
set_property -name "options.max_paths" -value "10" -objects $obj
}
# Create 'impl_1_power_opt_report_timing_summary_0' report (if not found)
if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_power_opt_report_timing_summary_0] "" ] } {
create_report_config -report_name impl_1_power_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps power_opt_design -runs impl_1
}
set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_power_opt_report_timing_summary_0]
if { $obj != "" } {
set_property -name "is_enabled" -value "0" -objects $obj
set_property -name "options.max_paths" -value "10" -objects $obj
}
# Create 'impl_1_place_report_io_0' report (if not found)
if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_io_0] "" ] } {
create_report_config -report_name impl_1_place_report_io_0 -report_type report_io:1.0 -steps place_design -runs impl_1
}
set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_io_0]
if { $obj != "" } {
}
# Create 'impl_1_place_report_utilization_0' report (if not found)
if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_utilization_0] "" ] } {
create_report_config -report_name impl_1_place_report_utilization_0 -report_type report_utilization:1.0 -steps place_design -runs impl_1
}
set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_utilization_0]
if { $obj != "" } {
}
# Create 'impl_1_place_report_control_sets_0' report (if not found)
if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_control_sets_0] "" ] } {
create_report_config -report_name impl_1_place_report_control_sets_0 -report_type report_control_sets:1.0 -steps place_design -runs impl_1
}
set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_control_sets_0]
if { $obj != "" } {
set_property -name "options.verbose" -value "1" -objects $obj
}
# Create 'impl_1_place_report_incremental_reuse_0' report (if not found)
if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_0] "" ] } {
create_report_config -report_name impl_1_place_report_incremental_reuse_0 -report_type report_incremental_reuse:1.0 -steps place_design -runs impl_1
}
set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_0]
if { $obj != "" } {
set_property -name "is_enabled" -value "0" -objects $obj
}
# Create 'impl_1_place_report_incremental_reuse_1' report (if not found)
if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_1] "" ] } {
create_report_config -report_name impl_1_place_report_incremental_reuse_1 -report_type report_incremental_reuse:1.0 -steps place_design -runs impl_1
}
set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_1]
if { $obj != "" } {
set_property -name "is_enabled" -value "0" -objects $obj
}
# Create 'impl_1_place_report_timing_summary_0' report (if not found)
if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_timing_summary_0] "" ] } {
create_report_config -report_name impl_1_place_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps place_design -runs impl_1
}
set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_timing_summary_0]
if { $obj != "" } {
set_property -name "is_enabled" -value "0" -objects $obj
set_property -name "options.max_paths" -value "10" -objects $obj
}
# Create 'impl_1_post_place_power_opt_report_timing_summary_0' report (if not found)
if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_place_power_opt_report_timing_summary_0] "" ] } {
create_report_config -report_name impl_1_post_place_power_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps post_place_power_opt_design -runs impl_1
}
set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_place_power_opt_report_timing_summary_0]
if { $obj != "" } {
set_property -name "is_enabled" -value "0" -objects $obj
set_property -name "options.max_paths" -value "10" -objects $obj
}
# Create 'impl_1_phys_opt_report_timing_summary_0' report (if not found)
if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_phys_opt_report_timing_summary_0] "" ] } {
create_report_config -report_name impl_1_phys_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps phys_opt_design -runs impl_1
}
set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_phys_opt_report_timing_summary_0]
if { $obj != "" } {
set_property -name "is_enabled" -value "0" -objects $obj
set_property -name "options.max_paths" -value "10" -objects $obj
}
# Create 'impl_1_route_report_drc_0' report (if not found)
if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_drc_0] "" ] } {
create_report_config -report_name impl_1_route_report_drc_0 -report_type report_drc:1.0 -steps route_design -runs impl_1
}
set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_drc_0]
if { $obj != "" } {
}
# Create 'impl_1_route_report_methodology_0' report (if not found)
if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_methodology_0] "" ] } {
create_report_config -report_name impl_1_route_report_methodology_0 -report_type report_methodology:1.0 -steps route_design -runs impl_1
}
set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_methodology_0]
if { $obj != "" } {
}
# Create 'impl_1_route_report_power_0' report (if not found)
if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_power_0] "" ] } {
create_report_config -report_name impl_1_route_report_power_0 -report_type report_power:1.0 -steps route_design -runs impl_1
}
set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_power_0]
if { $obj != "" } {
}
# Create 'impl_1_route_report_route_status_0' report (if not found)
if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_route_status_0] "" ] } {
create_report_config -report_name impl_1_route_report_route_status_0 -report_type report_route_status:1.0 -steps route_design -runs impl_1
}
set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_route_status_0]
if { $obj != "" } {
}
# Create 'impl_1_route_report_timing_summary_0' report (if not found)
if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_timing_summary_0] "" ] } {
create_report_config -report_name impl_1_route_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps route_design -runs impl_1
}
set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_timing_summary_0]
if { $obj != "" } {
set_property -name "options.max_paths" -value "10" -objects $obj
}
# Create 'impl_1_route_report_incremental_reuse_0' report (if not found)
if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_incremental_reuse_0] "" ] } {
create_report_config -report_name impl_1_route_report_incremental_reuse_0 -report_type report_incremental_reuse:1.0 -steps route_design -runs impl_1
}
set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_incremental_reuse_0]
if { $obj != "" } {
}
# Create 'impl_1_route_report_clock_utilization_0' report (if not found)
if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_clock_utilization_0] "" ] } {
create_report_config -report_name impl_1_route_report_clock_utilization_0 -report_type report_clock_utilization:1.0 -steps route_design -runs impl_1
}
set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_clock_utilization_0]
if { $obj != "" } {
}
# Create 'impl_1_route_report_bus_skew_0' report (if not found)
if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_bus_skew_0] "" ] } {
create_report_config -report_name impl_1_route_report_bus_skew_0 -report_type report_bus_skew:1.1 -steps route_design -runs impl_1
}
set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_bus_skew_0]
if { $obj != "" } {
set_property -name "options.warn_on_violation" -value "1" -objects $obj
}
# Create 'impl_1_post_route_phys_opt_report_timing_summary_0' report (if not found)
if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_timing_summary_0] "" ] } {
create_report_config -report_name impl_1_post_route_phys_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps post_route_phys_opt_design -runs impl_1
}
set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_timing_summary_0]
if { $obj != "" } {
set_property -name "options.max_paths" -value "10" -objects $obj
set_property -name "options.warn_on_violation" -value "1" -objects $obj
}
# Create 'impl_1_post_route_phys_opt_report_bus_skew_0' report (if not found)
if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_bus_skew_0] "" ] } {
create_report_config -report_name impl_1_post_route_phys_opt_report_bus_skew_0 -report_type report_bus_skew:1.1 -steps post_route_phys_opt_design -runs impl_1
}
set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_bus_skew_0]
if { $obj != "" } {
set_property -name "options.warn_on_violation" -value "1" -objects $obj
}
set obj [get_runs impl_1]
set_property -name "needs_refresh" -value "1" -objects $obj
set_property -name "strategy" -value "Performance_RefinePlacement" -objects $obj
set_property -name "steps.place_design.args.directive" -value "ExtraPostPlacementOpt" -objects $obj
set_property -name "steps.phys_opt_design.args.directive" -value "Explore" -objects $obj
set_property -name "steps.route_design.args.directive" -value "Explore" -objects $obj
set_property -name "steps.write_bitstream.args.bin_file" -value "1" -objects $obj
set_property -name "steps.write_bitstream.args.readback_file" -value "0" -objects $obj
set_property -name "steps.write_bitstream.args.verbose" -value "0" -objects $obj
# set the current impl run
current_run -implementation [get_runs impl_1]
puts "INFO: Project created:${_xil_proj_name_}"
# Create 'drc_1' gadget (if not found)
if {[string equal [get_dashboard_gadgets [ list "drc_1" ] ] ""]} {
create_dashboard_gadget -name {drc_1} -type drc
}
set obj [get_dashboard_gadgets [ list "drc_1" ] ]
set_property -name "reports" -value "impl_1#impl_1_route_report_drc_0" -objects $obj
# Create 'methodology_1' gadget (if not found)
if {[string equal [get_dashboard_gadgets [ list "methodology_1" ] ] ""]} {
create_dashboard_gadget -name {methodology_1} -type methodology
}
set obj [get_dashboard_gadgets [ list "methodology_1" ] ]
set_property -name "reports" -value "impl_1#impl_1_route_report_methodology_0" -objects $obj
# Create 'power_1' gadget (if not found)
if {[string equal [get_dashboard_gadgets [ list "power_1" ] ] ""]} {
create_dashboard_gadget -name {power_1} -type power
}
set obj [get_dashboard_gadgets [ list "power_1" ] ]
set_property -name "reports" -value "impl_1#impl_1_route_report_power_0" -objects $obj
# Create 'timing_1' gadget (if not found)
if {[string equal [get_dashboard_gadgets [ list "timing_1" ] ] ""]} {
create_dashboard_gadget -name {timing_1} -type timing
}
set obj [get_dashboard_gadgets [ list "timing_1" ] ]
set_property -name "reports" -value "impl_1#impl_1_route_report_timing_summary_0" -objects $obj
# Create 'utilization_1' gadget (if not found)
if {[string equal [get_dashboard_gadgets [ list "utilization_1" ] ] ""]} {
create_dashboard_gadget -name {utilization_1} -type utilization
}
set obj [get_dashboard_gadgets [ list "utilization_1" ] ]
set_property -name "reports" -value "synth_1#synth_1_synth_report_utilization_0" -objects $obj
set_property -name "run.step" -value "synth_design" -objects $obj
set_property -name "run.type" -value "synthesis" -objects $obj
# Create 'utilization_2' gadget (if not found)
if {[string equal [get_dashboard_gadgets [ list "utilization_2" ] ] ""]} {
create_dashboard_gadget -name {utilization_2} -type utilization
}
set obj [get_dashboard_gadgets [ list "utilization_2" ] ]
set_property -name "reports" -value "impl_1#impl_1_place_report_utilization_0" -objects $obj
move_dashboard_gadget -name {utilization_1} -row 0 -col 0
move_dashboard_gadget -name {power_1} -row 1 -col 0
move_dashboard_gadget -name {drc_1} -row 2 -col 0
move_dashboard_gadget -name {timing_1} -row 0 -col 1
move_dashboard_gadget -name {utilization_2} -row 1 -col 1
move_dashboard_gadget -name {methodology_1} -row 2 -col 1

46
rtl/src/bram_tdp.v Normal file
View file

@ -0,0 +1,46 @@
`timescale 1ns / 1ps
// taken from https://danstrother.com/2010/09/11/inferring-rams-in-fpgas/
// modified for one read/write-port and one read-only-port,
/// A parameterized, inferable, true dual-port, dual-clock block RAM in Verilog.
module bram_tdp #(
parameter DATA = 72,
parameter ADDR = 10
) (
// Port A
input wire a_clk,
input wire a_rd,
input wire a_wr,
input wire [ADDR-1:0] a_addr,
input wire [DATA-1:0] a_din,
output reg [DATA-1:0] a_dout,
// Port B
input wire b_clk,
input wire [ADDR-1:0] b_addr,
output reg [DATA-1:0] b_dout,
input wire b_rd
);
// Shared memory
reg [DATA-1:0] mem [(2**ADDR)-1:0];
wire a_en = a_rd || a_wr;
// Port A
always @(posedge a_clk) begin
if(a_en)
begin
if(a_wr)
mem[a_addr] <= a_din;
else if(a_rd)
a_dout <= mem[a_addr];
end
end
// Port B
always @(posedge b_clk) begin
if(b_rd)
b_dout <= mem[b_addr];
end
endmodule

83
rtl/src/cpuclk.v Normal file
View file

@ -0,0 +1,83 @@
`timescale 1ns / 1ps
module cpu_clkgen(
input wire rst,
input wire clk100,
output wire cpuclk,
output wire dram_refclk,
output wire pixclk,
output wire locked
);
wire cpuclk_pre, clk_fb, refclk_pre, pixclk_pre;
MMCME2_BASE #(
.BANDWIDTH("OPTIMIZED"), // Jitter programming (OPTIMIZED, HIGH, LOW)
.CLKFBOUT_MULT_F(10.0), // Multiply value for all CLKOUT (2.000-64.000).
.CLKFBOUT_PHASE(0.0), // Phase offset in degrees of CLKFB (-360.000-360.000).
.CLKIN1_PERIOD(10.0), // Input clock period in ns to ps resolution (i.e. 33.333 is 30 MHz).
// CLKOUT0_DIVIDE - CLKOUT6_DIVIDE: Divide amount for each CLKOUT (1-128)
.CLKOUT0_DIVIDE_F(12.0), // Divide amount for CLKOUT0 (1.000-128.000).
.CLKOUT1_DIVIDE(5),
.CLKOUT2_DIVIDE(40), // 40 = 25MHz pixel clock (should be 25.175MHz per spec) for 640x480
//.CLKOUT2_DIVIDE(25), // 25 = 40MHz pixel clock for 800x600
//.CLKOUT2_DIVIDE(15), // 15 = 66.66MHz pixel clock (should be 65.0Mhz per spec) for 1024x768
.CLKOUT3_DIVIDE(1),
.CLKOUT4_DIVIDE(1),
.CLKOUT5_DIVIDE(1),
.CLKOUT6_DIVIDE(1),
// CLKOUT0_DUTY_CYCLE - CLKOUT6_DUTY_CYCLE: Duty cycle for each CLKOUT (0.01-0.99).
.CLKOUT0_DUTY_CYCLE(0.5),
.CLKOUT1_DUTY_CYCLE(0.5),
.CLKOUT2_DUTY_CYCLE(0.5),
.CLKOUT3_DUTY_CYCLE(0.5),
.CLKOUT4_DUTY_CYCLE(0.5),
.CLKOUT5_DUTY_CYCLE(0.5),
.CLKOUT6_DUTY_CYCLE(0.5),
// CLKOUT0_PHASE - CLKOUT6_PHASE: Phase offset for each CLKOUT (-360.000-360.000).
.CLKOUT0_PHASE(0.0),
.CLKOUT1_PHASE(0.0),
.CLKOUT2_PHASE(0.0),
.CLKOUT3_PHASE(0.0),
.CLKOUT4_PHASE(0.0),
.CLKOUT5_PHASE(0.0),
.CLKOUT6_PHASE(0.0),
.CLKOUT4_CASCADE("FALSE"), // Cascade CLKOUT4 counter with CLKOUT6 (FALSE, TRUE)
.DIVCLK_DIVIDE(1), // Master division value (1-106)
.REF_JITTER1(0.010), // Reference input jitter in UI (0.000-0.999).
.STARTUP_WAIT("FALSE") // Delays DONE until MMCM is locked (FALSE, TRUE)
)
MMCME2_BASE_inst (
/* verilator lint_off PINCONNECTEMPTY */
// Clock Outputs: 1-bit (each) output: User configurable clock outputs
.CLKOUT0(cpuclk_pre), // 1-bit output: CLKOUT0
.CLKOUT0B(), // 1-bit output: Inverted CLKOUT0
.CLKOUT1(refclk_pre), // 1-bit output: CLKOUT1
.CLKOUT1B(), // 1-bit output: Inverted CLKOUT1
.CLKOUT2(pixclk_pre), // 1-bit output: CLKOUT2
.CLKOUT2B(), // 1-bit output: Inverted CLKOUT2
.CLKOUT3(), // 1-bit output: CLKOUT3
.CLKOUT3B(), // 1-bit output: Inverted CLKOUT3
.CLKOUT4(), // 1-bit output: CLKOUT4
.CLKOUT5(), // 1-bit output: CLKOUT5
.CLKOUT6(), // 1-bit output: CLKOUT6
// Feedback Clocks: 1-bit (each) output: Clock feedback ports
.CLKFBOUT(clk_fb), // 1-bit output: Feedback clock
.CLKFBOUTB(), // 1-bit output: Inverted CLKFBOUT
// Status Ports: 1-bit (each) output: MMCM status ports
.LOCKED(locked), // 1-bit output: LOCK
// Clock Inputs: 1-bit (each) input: Clock input
.CLKIN1(clk100), // 1-bit input: Clock
// Control Ports: 1-bit (each) input: MMCM control ports
.PWRDWN(), // 1-bit input: Power-down
/* verilator lint_on PINCONNECTEMPTY */
.RST(rst), // 1-bit input: Reset
// Feedback Clocks: 1-bit (each) input: Clock feedback ports
.CLKFBIN(clk_fb) // 1-bit input: Feedback clock
);
BUFG bufg_cpuclk(.I(cpuclk_pre), .O(cpuclk));
BUFG bufg_refclk(.I(refclk_pre), .O(dram_refclk));
BUFG bufg_pixclk(.I(pixclk_pre), .O(pixclk));
endmodule

96
rtl/src/display_clock.v Normal file
View file

@ -0,0 +1,96 @@
`timescale 1ns / 1ps
`default_nettype none
// Project F: Display Clocks
// (C)2019 Will Green, Open source hardware released under the MIT License
// Learn more at https://projectf.io
// Defaults to 25.2 and 126 MHz for 640x480 at 60 Hz
module display_clock #(
MULT_MASTER=31.5, // master clock multiplier (2.000-64.000)
DIV_MASTER=5, // master clock divider (1-106)
DIV_5X=5.0, // 5x clock divider (1-128)
DIV_1X=25, // 1x clock divider (1-128)
IN_PERIOD=10.0 // period of i_clk in ns (100 MHz = 10.0 ns)
)
(
input wire i_clk, // input clock
input wire i_rst, // reset (active high)
output wire o_clk_1x, // pixel clock
output wire o_clk_5x, // 5x clock for 10:1 DDR SerDes
output wire o_locked // clock locked? (active high)
);
wire clk_fb; // internal clock feedback
wire clk_1x_pre;
wire clk_5x_pre;
MMCME2_BASE #(
.BANDWIDTH("OPTIMIZED"), // Jitter programming (OPTIMIZED, HIGH, LOW)
.CLKFBOUT_MULT_F(MULT_MASTER), // Multiply value for all CLKOUT (2.000-64.000).
.CLKFBOUT_PHASE(0.0), // Phase offset in degrees of CLKFB (-360.000-360.000).
.CLKIN1_PERIOD(IN_PERIOD), // Input clock period in ns to ps resolution (i.e. 33.333 is 30 MHz).
// CLKOUT0_DIVIDE - CLKOUT6_DIVIDE: Divide amount for each CLKOUT (1-128)
.CLKOUT0_DIVIDE_F(DIV_5X), // Divide amount for CLKOUT0 (1.000-128.000).
.CLKOUT1_DIVIDE(DIV_1X),
.CLKOUT2_DIVIDE(1),
.CLKOUT3_DIVIDE(1),
.CLKOUT4_DIVIDE(1),
.CLKOUT5_DIVIDE(1),
.CLKOUT6_DIVIDE(1),
// CLKOUT0_DUTY_CYCLE - CLKOUT6_DUTY_CYCLE: Duty cycle for each CLKOUT (0.01-0.99).
.CLKOUT0_DUTY_CYCLE(0.5),
.CLKOUT1_DUTY_CYCLE(0.5),
.CLKOUT2_DUTY_CYCLE(0.5),
.CLKOUT3_DUTY_CYCLE(0.5),
.CLKOUT4_DUTY_CYCLE(0.5),
.CLKOUT5_DUTY_CYCLE(0.5),
.CLKOUT6_DUTY_CYCLE(0.5),
// CLKOUT0_PHASE - CLKOUT6_PHASE: Phase offset for each CLKOUT (-360.000-360.000).
.CLKOUT0_PHASE(0.0),
.CLKOUT1_PHASE(0.0),
.CLKOUT2_PHASE(0.0),
.CLKOUT3_PHASE(0.0),
.CLKOUT4_PHASE(0.0),
.CLKOUT5_PHASE(0.0),
.CLKOUT6_PHASE(0.0),
.CLKOUT4_CASCADE("FALSE"), // Cascade CLKOUT4 counter with CLKOUT6 (FALSE, TRUE)
.DIVCLK_DIVIDE(DIV_MASTER), // Master division value (1-106)
.REF_JITTER1(0.010), // Reference input jitter in UI (0.000-0.999).
.STARTUP_WAIT("FALSE") // Delays DONE until MMCM is locked (FALSE, TRUE)
)
MMCME2_BASE_inst (
/* verilator lint_off PINCONNECTEMPTY */
// Clock Outputs: 1-bit (each) output: User configurable clock outputs
.CLKOUT0(clk_5x_pre), // 1-bit output: CLKOUT0
.CLKOUT0B(), // 1-bit output: Inverted CLKOUT0
.CLKOUT1(clk_1x_pre), // 1-bit output: CLKOUT1
.CLKOUT1B(), // 1-bit output: Inverted CLKOUT1
.CLKOUT2(), // 1-bit output: CLKOUT2
.CLKOUT2B(), // 1-bit output: Inverted CLKOUT2
.CLKOUT3(), // 1-bit output: CLKOUT3
.CLKOUT3B(), // 1-bit output: Inverted CLKOUT3
.CLKOUT4(), // 1-bit output: CLKOUT4
.CLKOUT5(), // 1-bit output: CLKOUT5
.CLKOUT6(), // 1-bit output: CLKOUT6
// Feedback Clocks: 1-bit (each) output: Clock feedback ports
.CLKFBOUT(clk_fb), // 1-bit output: Feedback clock
.CLKFBOUTB(), // 1-bit output: Inverted CLKFBOUT
// Status Ports: 1-bit (each) output: MMCM status ports
.LOCKED(o_locked), // 1-bit output: LOCK
// Clock Inputs: 1-bit (each) input: Clock input
.CLKIN1(i_clk), // 1-bit input: Clock
// Control Ports: 1-bit (each) input: MMCM control ports
.PWRDWN(), // 1-bit input: Power-down
/* verilator lint_on PINCONNECTEMPTY */
.RST(i_rst), // 1-bit input: Reset
// Feedback Clocks: 1-bit (each) input: Clock feedback ports
.CLKFBIN(clk_fb) // 1-bit input: Feedback clock
);
// explicitly buffer output clocks
BUFG bufg_clk_pix(.I(clk_1x_pre), .O(o_clk_1x));
BUFG bufg_clk_pix_5x(.I(clk_5x_pre), .O(o_clk_5x));
endmodule

165
rtl/src/dram_bridge.v Normal file
View file

@ -0,0 +1,165 @@
`timescale 1ns / 1ps
module dram_bridge #(ADDR_WIDTH = 32, WIDTH = 32)
(
// local bus
input wire [ADDR_WIDTH-1:0] mem_addr,
output wire [WIDTH-1:0] mem_read_data,
input wire [WIDTH-1:0] mem_write_data,
input wire mem_read_enable,
input wire mem_write_enable,
output wire mem_wait,
input wire rst_n,
input wire dram_front_clk,
input wire dram_refclk,
// DDR3 SDRAM
inout wire [15:0] ddr3_dq,
inout wire [1:0] ddr3_dqs_n,
inout wire [1:0] ddr3_dqs_p,
output wire [13:0] ddr3_addr,
output wire [2:0] ddr3_ba,
output wire ddr3_ras_n,
output wire ddr3_cas_n,
output wire ddr3_we_n,
output wire ddr3_reset_n,
output wire [0:0] ddr3_ck_p,
output wire [0:0] ddr3_ck_n,
output wire [0:0] ddr3_cke,
output wire [0:0] ddr3_cs_n,
output wire [1:0] ddr3_dm,
output wire [0:0] ddr3_odt
);
localparam DRAM_ADDR_WIDTH = 28, DRAM_DATA_WIDTH = 128, DRAM_MASK_WIDTH = 16;
wire [DRAM_ADDR_WIDTH-1:0] app_addr;
wire [2:0] app_cmd;
wire app_en;
wire app_rdy;
wire [DRAM_DATA_WIDTH-1:0] app_rd_data;
wire app_rd_data_end;
wire app_rd_data_valid;
wire [DRAM_DATA_WIDTH-1:0] app_wdf_data;
wire app_wdf_end;
wire [DRAM_MASK_WIDTH-1:0] app_wdf_mask;
wire app_wdf_rdy;
wire app_sr_active;
wire app_ref_ack;
wire app_zq_ack;
wire app_wdf_wren;
wire [11:0] device_temp;
wire ui_clk, ui_rst_sync;
wire init_calib_complete;
localparam CMD_READ = 3'b1;
localparam CMD_WRITE = 3'b0;
mig_dram_0 dram0(
// Inouts
.ddr3_dq(ddr3_dq),
.ddr3_dqs_n(ddr3_dqs_n),
.ddr3_dqs_p(ddr3_dqs_p),
// Outputs
.ddr3_addr(ddr3_addr),
.ddr3_ba(ddr3_ba),
.ddr3_ras_n(ddr3_ras_n),
.ddr3_cas_n(ddr3_cas_n),
.ddr3_we_n(ddr3_we_n),
.ddr3_reset_n(ddr3_reset_n),
.ddr3_ck_p(ddr3_ck_p),
.ddr3_ck_n(ddr3_ck_n),
.ddr3_cke(ddr3_cke),
.ddr3_cs_n(ddr3_cs_n),
.ddr3_dm(ddr3_dm),
.ddr3_odt(ddr3_odt),
// Application interface ports
.app_addr (app_addr),
.app_cmd (app_cmd),
.app_en (app_en),
.app_wdf_data (app_wdf_data),
.app_wdf_mask (app_wdf_mask),
.app_wdf_end (app_wdf_end),
.app_wdf_wren (app_wdf_wren),
.app_rd_data (app_rd_data),
.app_rd_data_end (app_rd_data_end),
.app_rd_data_valid (app_rd_data_valid),
.app_rdy (app_rdy),
.app_wdf_rdy (app_wdf_rdy),
.app_sr_req (1'b0),
.app_ref_req (1'b0),
.app_zq_req (1'b0),
.app_sr_active (app_sr_active),
.app_ref_ack (app_ref_ack),
.app_zq_ack (app_zq_ack),
.ui_clk (ui_clk),
.ui_clk_sync_rst (ui_rst_sync),
// System Clock Ports
.sys_clk_i (dram_front_clk),
// Reference Clock Ports
.clk_ref_i (dram_refclk),
.device_temp (device_temp),
.init_calib_complete (init_calib_complete),
.sys_rst (rst_n)
);
// reg [DRAM_DATA_WIDTH-1:0] read_cache;
// reg [ADDR_WIDTH-1:0] cached_addr;
// wire cache_hit = cached_addr == mem_addr;
// wire [DRAM_DATA_WIDTH-1:0] read_data_wrapper = cache_hit ? read_cache : app_rd_data;
reg [WIDTH-1:0] read_buf;
reg read_inprogress = 0;
assign app_rd_data_end = 1'b1;
//assign app_wdf_mask = 16'b1111111111111100;
// addresses on the memory interface are aligned to 16 bytes
// and 28 bits wide (=256MB)
assign app_addr = { mem_addr[DRAM_ADDR_WIDTH:4], 4'b0000 };
//assign app_addr = { 28'b0 };
// select a word from the 128 bits transferred by the dram controller
// according to the lower bits of the address (ignoring bits 1:0)
wire [WIDTH-1:0] read_word;
wire [1:0] word_sel = mem_addr[3:2];
assign read_word = word_sel == 3'b11 ? app_rd_data[31:0] :
word_sel == 3'b10 ? app_rd_data[63:32] :
word_sel == 3'b01 ? app_rd_data[95:64] :
app_rd_data[127:96];
assign mem_read_data = app_rd_data_valid ? read_word : read_buf;
// set the write mask according to the lower bits of the address
// (ignoring bit 0)
assign app_wdf_mask = word_sel == 3'b11 ? 16'b1111111111110000 :
word_sel == 3'b10 ? 16'b1111111100001111 :
word_sel == 3'b01 ? 16'b1111000011111111 :
16'b0000111111111111 ;
wire write_ready = mem_write_enable & app_wdf_rdy & app_rdy;
assign app_wdf_wren = mem_write_enable & write_ready;
assign app_wdf_end = mem_write_enable & write_ready;
assign app_wdf_data = { {4{mem_write_data}} };
assign mem_wait = (mem_read_enable & ~read_inprogress) |
(mem_write_enable & (~app_wdf_rdy | ~app_rdy)) |
(read_inprogress & ~app_rd_data_valid);
assign app_en = (mem_read_enable & ~read_inprogress) |
(mem_write_enable & write_ready);
assign app_cmd = mem_read_enable ? CMD_READ : CMD_WRITE;
always @(posedge dram_front_clk)
begin
if(mem_read_enable & ~read_inprogress & app_rdy)
read_inprogress <= 1;
if(read_inprogress & app_rd_data_valid)
read_inprogress <= 0;
if(mem_read_enable & app_rd_data_valid)
read_buf <= mem_read_data;
end
endmodule

53
rtl/src/fifo.v Normal file
View file

@ -0,0 +1,53 @@
`timescale 1ns / 1ps
// a simple fifo
module fifo #(parameter DATA_WIDTH = 8, ADDR_WIDTH = 4)(
input wire clk,
input wire reset,
input wire wr_en,
input wire rd_en,
input wire [DATA_WIDTH-1:0] wr_data,
output wire [DATA_WIDTH-1:0] rd_data,
output wire wr_full,
output wire rd_empty
);
reg [DATA_WIDTH-1:0] mem [0:2**ADDR_WIDTH-1];
reg [ADDR_WIDTH:0] head_x = 0; // head and tail have one extra bit
reg [ADDR_WIDTH:0] tail_x = 0; // for detecting overflows
wire [ADDR_WIDTH-1:0] head = head_x[ADDR_WIDTH-1:0];
wire [ADDR_WIDTH-1:0] tail = tail_x[ADDR_WIDTH-1:0];
assign rd_data = mem[tail];
// the fifo is full when head and tail pointer are the same
// and the extra bits differ (a wraparound occured)
assign wr_full = (head == tail) && (head_x[ADDR_WIDTH] != tail_x[ADDR_WIDTH]);
// the fifo is empty when head and tail pointer are the same
// and the extra bits are the same (no wraparound)
assign rd_empty = (head == tail) && (head_x[ADDR_WIDTH] == tail_x[ADDR_WIDTH]);
// Writing to FIFO
always @(posedge clk) begin
if (reset)
head_x <= 0;
else if (wr_en)
begin
mem[head] <= wr_data;
// move head, possible wraparound
head_x <= head_x + 1'b1;
end
end
// Reading from FIFO
always @(posedge clk)
begin
if (reset)
tail_x <= 0;
else if (rd_en)
begin
// rd_data always has current tail data
// move tail, possible wraparound
tail_x <= tail_x + 1'b1;
end
end
endmodule

116
rtl/src/fifo_testbench.v Normal file
View file

@ -0,0 +1,116 @@
`timescale 1ns / 1ns
`default_nettype none
module fifo_testbench();
// Test signals
reg clk = 0;
reg reset = 0;
reg wr_en = 0;
reg rd_en = 0;
reg [7:0] wr_data = 0;
wire [7:0] rd_data;
wire wr_full;
wire rd_empty;
parameter CLOCK_NS = 10;
// Unit Under Test
fifo #(
.DATA_WIDTH(8),
.ADDR_WIDTH(4)
) UUT (
.clk(clk),
.reset(reset),
.wr_en(wr_en),
.rd_en(rd_en),
.rd_data(rd_data),
.wr_data(wr_data),
.wr_full(wr_full),
.rd_empty(rd_empty)
);
// testbench clock
always
#(CLOCK_NS/2) clk <= ~clk;
initial
begin
// issue reset
reset = 1'b1;
#10
reset = 1'b0;
#10
// Write two bytes
wr_data <= 8'hAB;
wr_en <= 1'b1;
#10;
wr_data <= 8'hCD;
wr_en <= 1'b1;
#10;
wr_en <= 1'b0;
#10
// read fifo tail
if (rd_data == 8'hAB)
$display("Pass - Byte 1");
else
$display("Failed - Byte 2");
// read/remove byte from tail
rd_en <= 1'b1;
#10
// check next byte
if (rd_data == 8'hCD)
$display("Pass - Byte 2");
else
$display("Failed - Byte 2");
// remove 2nd byte
rd_en <= 1'b1;
#10
rd_en <= 1'b0;
#10
// Write until full
rd_en <= 1'b0;
wr_en <= 1'b0;
for (integer i = 0; i < 16; i = i + 1) begin
wr_data <= i;
wr_en <= 1'b1;
#10;
end
wr_en <= 1'b0;
if (wr_full)
$display("Pass - Fifo full");
else
$display("Failed - Fifo full");
// read until empty
rd_en <= 1'b0;
wr_en <= 1'b0;
for (integer i = 0; i < 16; i = i + 1) begin
rd_en <= 1'b1;
#10;
end
rd_en <= 1'b0;
if (rd_empty)
$display("Pass - Fifo empty");
else
$display("Failed - Fifo empty");
$finish();
end
initial
begin
// Required to dump signals
$dumpfile("fifo_tb_dump.vcd");
$dumpvars(0);
end
endmodule

73
rtl/src/irqctrl.v Normal file
View file

@ -0,0 +1,73 @@
`timescale 1ns / 1ps
module irqctrl #(IRQ_LINES = 2, IRQ_DELAY_WIDTH = 4) (
input wire clk,
input wire [IRQ_LINES-1:0] irq_in,
input wire cs,
input wire wr_en,
input wire irq_wr_seten,
output wire [IRQ_LINES-1:0] rd_data,
output wire irq_out
);
reg [IRQ_LINES-1:0] irq_status; // a 1 bit here means we have seen an interrupt on that line
reg [IRQ_LINES-1:0] irq_mask; // a bit in irq_status is only set if the corresponding bit in irq_mask is not set
// irq_mask is set from irq_status when an interrupt occurs (ie irq_out is set)
reg irq_enabled; // globally enable/disable irq_out
reg [IRQ_DELAY_WIDTH-1:0] irq_delay; // counter to delay irq_out for a few cycles
reg irq_delaying; // delay is active
wire irq_pending = (irq_status != 0);
assign rd_data = irq_mask;
assign irq_out = irq_enabled && irq_pending && !irq_delaying;
// irq_status and irq_pending flags
always @(posedge clk)
begin
if(irq_out) // when an interrupt is being signaled to the cpu,
irq_status <= 0; // clear irq status, status will be copied to irq_mask (see below)
else
if(irq_in != 0)
irq_status <= irq_status | (irq_in & ~irq_mask); // add active irq to irq_status
end
// irq mask
always @(posedge clk)
begin
if (cs && wr_en && irq_wr_seten) // when enabling interrupts, clear mask
irq_mask <= 0;
else
if(irq_out) // when signalling an interrupt, set mask from status
irq_mask <= irq_status;
end
// manage irq_enabled and irq_delay/irq_delaying
always @(posedge clk)
begin
if(cs && wr_en) // when writing to control register
begin
if(irq_wr_seten) // if wr_seten flag is set, enable interrupts and start delay
begin
irq_enabled <= 1;
irq_delaying <= 1;
irq_delay <= 1;
end
else
irq_enabled <= 0; // else disable interrupts
end
else if(irq_out) irq_enabled <= 0; // after sending interrupt to cpu, disable further interrupts
if(irq_delaying) // the delay gives the CPU a chance to return from an interrupt handler
begin // if an interrupt is triggered again right after re-enabling interrupts
if(irq_delay==0)
begin
irq_delay <= 1;
irq_delaying <= 0;
end
else
irq_delay <= irq_delay + 1;
end
end
endmodule

161
rtl/src/mem.v Normal file
View file

@ -0,0 +1,161 @@
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 05.01.2021 21:53:41
// Design Name:
// Module Name: mem
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
// 32 bit wide rom with byte addressing (address bits 1-0 are ignored)
module rom32 #(parameter ADDR_WIDTH = 11, DATA_WIDTH = 32)
(
input wire clk,
input wire [ADDR_WIDTH-1:0] addr,
output reg [DATA_WIDTH-1:0] data_out,
input wire read_enable
);
wire [ADDR_WIDTH-2:0] internal_addr = addr[ADDR_WIDTH-1:2]; // -> ignore bit 0
reg [DATA_WIDTH-1:0] rom [0:(2**(ADDR_WIDTH-2))-1];
initial begin
$readmemb("C:\\Users\\sebastian\\develop\\fpga\\vdumbcpu\\rom.mem", rom);
end
always @(posedge clk) data_out <= rom[internal_addr];
endmodule
module ram32 #(parameter ADDR_WIDTH = 16, DATA_WIDTH = 32)
(
input wire clk,
input wire [ADDR_WIDTH-1:0] addr,
output reg [DATA_WIDTH-1:0] data_out,
input wire read_enable,
input wire [DATA_WIDTH-1:0] data_in,
input wire write_enable
);
reg [DATA_WIDTH-1:0] ram [0:(2**(ADDR_WIDTH-2))-1]; // 32bit words with byte addressing
wire [ADDR_WIDTH-2:0] internal_addr = addr[ADDR_WIDTH-1:2]; // -> ignore bit 1-0
always @(posedge clk)
begin
if(read_enable)
data_out <= ram[internal_addr];
if(write_enable)
ram[internal_addr] <= data_in;
end
endmodule
module mem #(parameter ADDR_WIDTH = 32,
parameter DATA_WIDTH = 32)
(
input wire clk, rst_n,
input wire [ADDR_WIDTH-1:0] addr,
output wire [DATA_WIDTH-1:0] data_out,
input wire read_enable,
input wire [DATA_WIDTH-1:0] data_in,
input wire write_enable,
output wire io_enable,
input wire [DATA_WIDTH-1:0] io_rd_data,
output wire mem_wait,
output wire [ADDR_WIDTH-1:0] dram_addr,
input wire [DATA_WIDTH-1:0] dram_read_data,
output wire [DATA_WIDTH-1:0] dram_write_data,
output wire dram_read_enable,
output wire dram_write_enable,
input wire dram_wait
);
wire [DATA_WIDTH-1:0] ram_out, rom_out, dram_out;
// address map:
// ROM $0000 - $07FF 2K
// IO $0800 - $0FFF 2K
// RAM1 $1000 - $FFFF 60K
// RAM2 $10000 - $FFFFFFFF ~4GB
wire ram_cs = addr[ADDR_WIDTH-1:12] != { {(ADDR_WIDTH-12){1'b0}}};
wire ram1_cs = ram_cs && (addr[ADDR_WIDTH-1:16] == { {(ADDR_WIDTH-16){1'b0}}});
wire ram2_cs = ram_cs && !ram1_cs;
wire rom_cs = !ram_cs && addr[11] == 1'b0;
wire io_cs = !ram_cs && addr[11] == 1'b1;
assign io_enable = io_cs;
wire ram_read = ram1_cs && read_enable;
wire ram_write = ram1_cs && write_enable;
wire rom_read = rom_cs && read_enable;
reg [DATA_WIDTH-1:0] data_buf;
localparam SEL_RAM1 = 0;
localparam SEL_RAM2 = 1;
localparam SEL_ROM = 2;
localparam SEL_IO = 3;
localparam SEL_ERR = 4;
reg [1:0] out_sel;
// test
reg [1:0] wait_state;
ram32 #(.ADDR_WIDTH(16)) ram0 // 64KB RAM
(
.clk(clk),
.addr(addr[15:0]),
.data_out(ram_out),
.read_enable(ram_read),
.data_in(data_in),
.write_enable(ram_write)
);
rom32 #(.ADDR_WIDTH(11)) rom0 // 2KB ROM
(
.clk(clk),
.addr(addr[10:0]),
.data_out(rom_out),
.read_enable(rom_read)
);
assign dram_out = dram_read_data;
assign dram_addr = addr;
assign dram_write_data = data_in;
assign dram_read_enable = ram2_cs & read_enable;
assign dram_write_enable = ram2_cs & write_enable;
assign data_out = (out_sel == SEL_RAM1 ) ? ram_out :
(out_sel == SEL_RAM2 ) ? dram_out :
(out_sel == SEL_ROM ) ? rom_out :
(out_sel == SEL_IO ) ? io_rd_data :
data_buf;
assign mem_wait = ram2_cs && dram_wait;
always @(posedge clk)
begin
data_buf <= data_out;
if(read_enable) out_sel <=
ram1_cs ? SEL_RAM1 :
ram2_cs ? SEL_RAM2:
rom_cs ? SEL_ROM :
io_cs ? SEL_IO :
SEL_ERR;
end
endmodule

28
rtl/src/palette.v Normal file
View file

@ -0,0 +1,28 @@
`timescale 1ns / 1ps
// taken from https://danstrother.com/2010/09/11/inferring-rams-in-fpgas/
// modified for one read/write-port and one read-only-port,
/// A parameterized, inferable, true dual-port, dual-clock block RAM in Verilog.
module palette #(
parameter SLOTS_WIDTH = 4, COLOR_WIDTH = 12
) (
input wire wr_clk,
input wire rd_clk,
input wire wr_en,
input wire [SLOTS_WIDTH-1:0] wr_slot,
input wire [COLOR_WIDTH-1:0] wr_data,
input wire [SLOTS_WIDTH-1:0] rd_slot,
output wire [COLOR_WIDTH-1:0] rd_data
);
// Shared memory
reg [COLOR_WIDTH-1:0] colors [(2**SLOTS_WIDTH)-1:0];
assign rd_data = colors[rd_slot];
always @(posedge wr_clk) begin
if(wr_en) colors[wr_slot] <= wr_data;
end
endmodule

372
rtl/src/sdspi.v Normal file
View file

@ -0,0 +1,372 @@
`timescale 1ns / 1ps
// Every spi_clk_div cpu clock cycles the spi clock line is inverted.
// So a spi clock cycle is 2*spi_clk_div cpu clock cycles.
// spi_clk_count counts the cpu cycles from spi_clk_div down to zero.
// The resulting spi clock frequency is:
// (cpu clock freq) / ((sclk_count + 1) * 2)
// So for a 83.33 MHz cpu clock, we get
// spi_clk_div = 10: 83.333 / 22 = 3.788 MHz
// spi_clk_div = 124: 83.333 / 250 = 333.33 KHz
module sdspi(
input wire clk, // bus clock
input wire reset,
input wire[7:0] tx_data, // data to transmit
output wire[7:0] rx_data, // data received
output wire tx_ready, // ready to write a data byte
output wire tx_empty, // transmitter fifo is empty
output wire rx_avail, // a byte has been received
output wire rx_ovr, // receiver overrun
input wire tx_write, // write strobe
input wire rx_read, // read strobe (clears rx_ovr)
output wire card_detect, // true is card is present
output wire card_changed, // card_detect signal has changed
output wire card_busy, // card is busy (MISO/DO is 0)
input wire ctrl_write, // set the following flags
input wire rx_filter_en, // set to discard received $FF bytes
input wire txrx_en, // enable transmitter and receiver
input wire spiclk_f_en, // enable spi clock without cs
input wire spiclk_div_wr, // set clock divider via tx_data
// PMOD connections
output wire sd_cs_n,
output reg sd_mosi,
input wire sd_miso,
output wire sd_sck,
input wire sd_cd
);
localparam CLKPHASE_0A = 2'b00;
localparam CLKPHASE_0B = 2'b01;
localparam CLKPHASE_1A = 2'b10;
localparam CLKPHASE_1B = 2'b11;
reg [1:0] clk_phase;
reg xcvr_on; // if turned off, the rest of the current byte
// will still transmitted, and until then "running"
// will be 1
(* KEEP *)
reg running; // transmitting/receiving a byte (maybe a dummy byte)
(* KEEP *) reg [3:0] xcvr_bitcount; // number of bits left of the current byte
reg [7:0] tx_shifter;
wire tx_fifo_wr_en;
reg tx_fifo_rd_en;
wire tx_fifo_full;
wire tx_fifo_empty;
wire [7:0] tx_fifo_out;
reg [7:0] rx_shifter;
reg rx_filter;
reg rx_fifo_wr_en;
wire rx_fifo_rd_en;
wire rx_fifo_full;
wire rx_fifo_empty;
wire [7:0] rx_fifo_out;
reg rx_bit_recvd; // this flag signals a received bit
reg rx_overrun; // byte received when rx fifo is full
reg c_changed;
reg c_cs;
reg spi_clk; // the spi clock signal
reg spi_clk_on; // enable clock, either via init mode or by xcvr_on
reg spi_clk_f_on; // init clock mode, i.e. start clock but no tx/rx
reg [6:0] spi_clk_count; // counting cpu clock ticks
reg [6:0] spi_clk_div; // tick counter for spi clock phases
wire spi_clk_count_z = (spi_clk_count == 7'b0);
reg hphase_start; // start of a spi clock half-phase
assign tx_ready = !tx_fifo_full;
assign tx_empty = tx_fifo_empty;
assign rx_avail = !rx_fifo_empty;
assign rx_ovr = rx_overrun;
assign rx_data = rx_fifo_out;
assign card_busy = (sd_miso == 0);
assign card_changed = c_changed;
assign sd_sck = spi_clk;
assign sd_cs_n = ~c_cs;
assign card_detect = sd_cd;
fifo #(.ADDR_WIDTH(4)) tx_fifo(clk, reset,
tx_fifo_wr_en, tx_fifo_rd_en,
tx_data, tx_fifo_out,
tx_fifo_full,
tx_fifo_empty
);
fifo #(.ADDR_WIDTH(8)) rx_fifo(clk, reset,
rx_fifo_wr_en, rx_fifo_rd_en,
rx_shifter, rx_fifo_out,
rx_fifo_full,
rx_fifo_empty
);
// spi clock
always @(posedge clk)
begin
if(reset)
begin
spi_clk <= 1; // CLK is high when inactive
spi_clk_on <= 0;
spi_clk_count <= 0;
end
else if(spi_clk_on)
begin
// set spi_clk at start of every half-phase
if(hphase_start)
case(clk_phase)
CLKPHASE_0A: spi_clk <= 1'b0;
CLKPHASE_0B: spi_clk <= 1'b0;
CLKPHASE_1A: spi_clk <= 1'b1;
CLKPHASE_1B: spi_clk <= 1'b1;
endcase
if(spi_clk_count_z)
begin
spi_clk_count <= spi_clk_div;
clk_phase <= clk_phase + 2'b1;
end
else
spi_clk_count <= spi_clk_count - 7'd1;
end
// start the clock if needed
if( (spi_clk_on == 0) && (running || spi_clk_f_on))
begin
spi_clk_on <= 1;
spi_clk_count <= spi_clk_div;
clk_phase <= CLKPHASE_1A;
end
// turn off the clock if transceiver not running
// and the force-clock-on flag is not set
if( (spi_clk_on == 1) && (!running && !spi_clk_f_on))
begin
spi_clk_on <= 0;
spi_clk <= 1'b1;
end
end
// half-phase-start flag trails spi_clk_count_z by one tick
always @(posedge clk)
begin
if(reset)
hphase_start <= 0;
else
hphase_start <= spi_clk_on && spi_clk_count_z;
end
// handle the force clock enable flag
always @(posedge clk)
begin
if (reset)
spi_clk_f_on <= 0;
else
if (ctrl_write)
spi_clk_f_on <= spiclk_f_en;
end
// clock divider
always @(posedge clk)
begin
if (spiclk_div_wr) spi_clk_div <= tx_data[6:0];
end
// card_changed flag
always @(posedge clk)
begin
if(sd_cd)
c_changed <= 1;
else if(ctrl_write || reset)
c_changed <= 0;
end
// cs signal
always @(posedge clk)
begin
if(hphase_start && clk_phase == CLKPHASE_0A || !running)
c_cs <= running;
end
// transmitter
always @(posedge clk)
begin
if(reset)
begin
// ???? we start the bitcount at 1 because we start
// at the second clock phase where the bitcount
// is decremented and the next byte gets loaded
xcvr_bitcount <= 0;
tx_shifter <= 8'b1;
xcvr_on <= 0;
sd_mosi <= 1;
tx_fifo_rd_en <= 0;
end
else
begin
// handle a control write to disable the transceiver
if(ctrl_write && !txrx_en && xcvr_on)
xcvr_on <= 0;
// a byte might still be in transit, so
// we do not disable the transceiver
// immediately (see "handle running status" below)
else
// handle control write to enable the transceiver
if(ctrl_write && txrx_en && !running)
begin
xcvr_on <= 1;
xcvr_bitcount <= 0;
// next clock phase must be 1B when starting the transceiver,
// so that the first byte is loaded into the shifter then
tx_shifter <= 8'b11111111;
// in case the transceiver is enabled, but no data is in the fifo,
// initialize the shifter with $FF
end
else
// handle clock phases
if (running)
begin
if(hphase_start)
case(clk_phase)
// set mosi signal at start of clock pulse
CLKPHASE_0A: sd_mosi <= tx_shifter[7];
CLKPHASE_0B: ;
CLKPHASE_1A: begin // shift at rising clock
tx_shifter <= tx_shifter << 1;
xcvr_bitcount <= xcvr_bitcount - 1;
end
CLKPHASE_1B: begin // in the middle of the high clock pulse,
// fetch the next byte if there are no bits
// left in the shift register
if (xcvr_bitcount == 0)
begin
if(!tx_fifo_empty)
begin
tx_shifter <= tx_fifo_out;
tx_fifo_rd_en <= 1;
end
else
tx_shifter <= 8'b11111111;
xcvr_bitcount <= 8;
end
else
tx_fifo_rd_en <= 0;
end
endcase
else
tx_fifo_rd_en <= 0;
end
end
end
// handle data write
assign tx_fifo_wr_en = tx_write && !tx_fifo_full;
// Enable fifo read signal if fifo is not empty.
// The data at the fifo tail is always available at
// rx_data, the read signal just moves the tail pointer
// forward.
assign rx_fifo_rd_en = rx_read && !rx_fifo_empty;
// receiver
always @(posedge clk)
begin
if(reset)
begin
rx_bit_recvd <= 0;
rx_shifter <= 8'b11111111;
rx_fifo_wr_en <= 0;
rx_filter <= 0;
rx_overrun <= 0;
end
else
begin
// handle a control write
if(ctrl_write)
begin
rx_filter <= rx_filter_en;
rx_overrun <= 0;
if(txrx_en && !running)
rx_shifter <= 8'b0;
end
if (running && hphase_start)
case(clk_phase)
CLKPHASE_0A: ;
CLKPHASE_0B: ;
CLKPHASE_1A: ;
CLKPHASE_1B: begin // in the middle of the high clock pulse,
// sample MISO and put into shift register
// and shift at the same time
rx_shifter <= { rx_shifter[6:0],sd_miso};
rx_bit_recvd <= 1;
end
endcase
if (rx_bit_recvd && !sd_cs_n && clk_phase == CLKPHASE_1B)
begin
rx_bit_recvd <= 0;
// if a complete byte was received, bitcount will be
// 8 because the transmitter has already loaded the next byte
// at this half-phase
if (xcvr_bitcount == 8)
begin
// discard $FF bytes if filter is enabled
if(!rx_filter || rx_shifter != 8'b11111111)
begin
if(rx_fifo_full) // discard received byte if fifo is full
rx_overrun <= 1; // and set overrun flag
else
rx_fifo_wr_en <= 1; // otherwise, enable fifo write strobe,
// fifo will take data from rx_shifter
end
// turn off filter if a byte != $FF was received
if (rx_filter && rx_shifter != 8'b11111111)
rx_filter <= 0;
end
end
else
rx_fifo_wr_en <= 0;
end
end
// handle running status
// (especially keep transmitter running when there are still bits left to be
// transmitted)
always@(posedge clk)
begin
if (reset)
running <= 0;
else
begin
// if we want to turn the transceiver on, set running flag
if (!running && xcvr_on)
running <= 1;
// when running and a byte has been transmitted,
// check if we should turn the transceiver off
if (running && hphase_start && xcvr_bitcount==0)
if(clk_phase == CLKPHASE_1B)
if (!xcvr_on)
running <= 0;
end
end
endmodule

199
rtl/src/sdspi_testbench.v Normal file
View file

@ -0,0 +1,199 @@
`timescale 1ns / 1ns
`default_nettype none
module sdspi_testbench();
parameter CLOCK_NS = 10;
integer i,j;
reg[7:0] rx_testdata[0:3];
reg[7:0] read_data;
// Test signals
reg clk = 0;
reg reset = 0;
reg[7:0] tx_data = 0;
wire[7:0] rx_data;
wire tx_ready;
wire tx_empty;
wire rx_avail;
wire rx_ovr;
reg tx_write = 0;
reg rx_read = 0;
wire card_detect;
wire card_changed;
wire card_busy;
reg ctrl_write = 0;
reg rx_filter_en = 0;
reg txrx_en = 0;
reg spiclk_f_en = 0;
reg spiclk_div_wr = 0;
// PMOD connections
wire sd_cs_n;
wire sd_mosi;
reg sd_miso = 1;
wire sd_sck;
reg sd_cd = 1;
// Unit Under Test
sdspi UUT (
.clk(clk),
.reset(reset),
.tx_data(tx_data),
.rx_data(rx_data),
.tx_ready(tx_ready),
.tx_empty(tx_empty),
.rx_avail(rx_avail),
.rx_ovr(rx_ovr),
.tx_write(tx_write),
.rx_read(rx_read),
.card_detect(card_detect),
.card_changed(card_changed),
.card_busy(card_busy),
.ctrl_write(ctrl_write),
.rx_filter_en(rx_filter_en),
.txrx_en(txrx_en),
.spiclk_f_en(spiclk_f_en),
.spiclk_div_wr(spiclk_div_wr),
.sd_cs_n(sd_cs_n),
.sd_mosi(sd_mosi),
.sd_miso(sd_miso),
.sd_sck(sd_sck),
.sd_cd(sd_cd)
);
// testbench clock
always
#(CLOCK_NS/2) clk <= ~clk;
initial
begin
rx_testdata[0] <= 'hFF;
rx_testdata[1] <= 'hFF;
rx_testdata[2] <= 'hCA;
rx_testdata[3] <= 'hFE;
// issue reset
reset = 1'b1;
#10
reset = 1'b0;
#10
// set clock divider
tx_data <= 3;
spiclk_div_wr <= 1'b1;
#10
spiclk_div_wr <= 1'b0;
#10
// Card initialization phase,
// cycle the clock at least 74 times
// while cs is off and mosi is high .
// we do 32 cycles
spiclk_f_en <= 1'b1;
ctrl_write <= 1'b1;
#10
spiclk_f_en <= 1'b0;
ctrl_write <= 1'b0;
#10
for (i=0; i<32*16; i = i + 1)
#10;
spiclk_f_en <= 1'b0;
ctrl_write <= 1'b1;
#10
ctrl_write <= 1'b0;
#10
for (i=0; i<32*16; i = i + 1)
#10;
// Write two bytes
tx_data <= 8'hAB;
tx_write <= 1'b1;
#10;
tx_data <= 8'hCD;
tx_write <= 1'b1;
#10;
tx_write <= 1'b0;
#10
// start transceiver, enable rx_filter
txrx_en <= 1'b1;
rx_filter_en <= 1'b1;
ctrl_write <= 1'b1;
#10
txrx_en <= 1'b0;
rx_filter_en <= 1'b0;
ctrl_write <= 1'b0;
for (i = 0; i < 2048; i = i + 1)
begin
if (!sd_cs_n && (i % 16)==15) sd_miso <= rx_testdata[(i/(16*8)) % 4][7 - (i/16 % 8)];
#10;
end
tx_write <= 1'b0;
#10
// read from rx fifo
read_data <= rx_data;
#10
$display("read data 1: %02h", read_data);
// strobe rx_read to go to next byte
rx_read <= 1'b1;
#10 // one cycle to transfer the data
rx_read <= 1'b0;
#10 // we need this extra cycle for the fifo tail to move
read_data <= rx_data;
#10
$display("read data 2: %02h", read_data);
// strobe rx_read to go to next byte
rx_read <= 1'b1;
#10
rx_read <= 1'b0;
#10 // we need this extra cycle for the fifo tail to move
read_data <= rx_data;
#10
$display("read data 3: %02h", read_data);
// set flag to turn transceiver off
txrx_en <= 1'b0;
ctrl_write <= 1'b1;
#10
ctrl_write <= 1'b0;
#10;
// wait for the transceiver to actually turn off
for (i=0; i<32*16; i = i + 1)
#10;
#10
// clear rx fifo
for(i=0; i<14; i = i + 1)
begin
$display("clear fifo data %02h", rx_data);
rx_read <= 1'b1;
#10
rx_read <= 1'b0;
#10
#10
#10; // simulate the four cycles of an instruction
end
$finish();
end
initial
begin
// Required to dump signals
$dumpfile("sdspi_tb_dump.vcd");
$dumpvars(0);
end
endmodule

42
rtl/src/stack.v Normal file
View file

@ -0,0 +1,42 @@
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 17.01.2021 20:59:29
// Design Name:
// Module Name: stack
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module stack
#(parameter ADDR_WIDTH=4, DATA_WIDTH=16)
(
input wire clk,
input wire [ADDR_WIDTH-1:0] rd_addr,
input wire [ADDR_WIDTH-1:0] wr_addr,
input wire wr_enable,
output wire [DATA_WIDTH-1:0] rd_data,
input wire [DATA_WIDTH-1:0] wr_data
);
reg [DATA_WIDTH-1:0] stack[0:2**ADDR_WIDTH-1];
always @(posedge clk)
begin
if(wr_enable) stack[wr_addr] <= wr_data;
end
assign rd_data = stack[rd_addr];
endmodule

427
rtl/src/stackcpu.v Normal file
View file

@ -0,0 +1,427 @@
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
module stackcpu #(parameter ADDR_WIDTH = 32, WIDTH = 32,
WORDSIZE = 4, WORDSIZE_SHIFT = 2) (
input wire clk,
input wire rst,
input wire irq,
output reg [ADDR_WIDTH-1:0] addr,
input wire [WIDTH-1:0] data_in,
output wire read_enable,
output wire [WIDTH-1:0] data_out,
output wire write_enable,
input wire mem_wait,
output wire led1,
output wire led2,
output wire led3,
output wire [WIDTH-1:0] debug_out1,
output wire [WIDTH-1:0] debug_out2,
output wire [WIDTH-1:0] debug_out3,
output wire [WIDTH-1:0] debug_out4,
output wire [WIDTH-1:0] debug_out5,
output wire [WIDTH-1:0] debug_out6
);
localparam EVAL_STACK_INDEX_WIDTH = 6;
wire reset = !rst;
(* KEEP *) reg [1:0] seq_state;
localparam FETCH = 2'b00; localparam DECODE = 2'b01; localparam EXEC = 2'b10; localparam MEM = 2'b11;
(* KEEP*) reg [WIDTH-1:0] X, nX;
wire [WIDTH-1:0] Y;
(* KEEP *) reg [WIDTH-1:0] PC, nPC;
reg [WIDTH-1:0] RP, nRP;
reg [WIDTH-1:0] FP, BP;
reg [WIDTH-1:0] IV,IR;
wire [WIDTH-1:0] pc_next_ins = PC + 2;
reg [EVAL_STACK_INDEX_WIDTH-1:0] ESP, nESP;
reg stack_write;
reg irq_pending;
// eval stack
stack #(.ADDR_WIDTH(EVAL_STACK_INDEX_WIDTH), .DATA_WIDTH(WIDTH)) estack (
.clk(clk),
.rd_addr(ESP),
.wr_addr(nESP),
.wr_enable(stack_write),
.rd_data(Y),
.wr_data(X)
);
reg [15:0] ins;
wire [WIDTH-1:0] operand;
// decoded instructions
wire ins_loadrel;
wire ins_load;
wire ins_loadc;
wire ins_store;
wire ins_aluop;
wire ins_ext;
wire ins_xfer;
wire ins_branch;
wire ins_cbranch;
// decoded extended instructions
wire ins_mem, ins_loadi, ins_storei;
wire ins_fpadj;
wire ins_reg, ins_loadreg, ins_storereg;
wire ins_reg_fp, ins_reg_bp, ins_reg_rp;
wire ins_reg_iv, ins_reg_ir;
wire ins_reg_esp;
wire loadstore_base;
wire cbranch_n;
wire xfer_x2p, xfer_r2p, xfer_p2r;
wire [1:0] xfer_rs;
wire [3:0] aluop;
wire [1:0] aluop_sd;
wire aluop_x2y, aluop_ext;
wire cmp_i, cmp_e, cmp_l;
wire mem_read;
wire mem_write;
wire x_is_zero;
// wire [WIDTH-1:0] y_plus_operand = Y + operand;
wire x_equals_y = X == Y;
wire y_lessthan_x = $signed(Y) < $signed(X);
wire yx_unsigned_less = Y < X;
reg [WIDTH-1:0] mem_write_data;
wire mem_read_enable, mem_write_enable;
assign read_enable = mem_read_enable;
assign data_out = mem_write_data;
assign write_enable = mem_write_enable;
// debug output ------------------------------------------------------------------------------------
assign led1 = reset;
assign led2 = ins_loadc;
assign led3 = ins_branch;
// assign debug_out1 = { mem_read_enable, mem_write_enable, x_is_zero,
// ins_branch, ins_aluop, y_lessthan_x, x_equals_y, {7{1'b0}}, seq_state};
// assign debug_out2 = data_in;
// assign debug_out3 = nX;
// assign debug_out4 = nPC;
// assign debug_out5 = ins;
// assign debug_out6 = IV;
//--------------------------------------------------------------------------------------------------
// instruction decoding
assign ins_branch = (ins[15:13] == 3'b000);
assign ins_aluop = (ins[15:13] == 3'b001);
assign ins_store = (ins[15:13] == 3'b010);
assign ins_xfer = (ins[15:13] == 3'b011);
assign ins_load = (ins[15:13] == 3'b100);
assign ins_cbranch = (ins[15:13] == 3'b101);
assign ins_loadc = (ins[15:13] == 3'b110);
assign ins_ext = (ins[15:13] == 3'b111);
// sub-decode LOAD/STORE
assign loadstore_base = ins[0];
// sub-decode CBRANCH
assign cbranch_n = ins[0];
// sub-decode XFER
assign xfer_x2p = ins[0];
assign xfer_r2p = ins[7];
assign xfer_p2r = ins[6];
assign xfer_rs = ins[9:8];
// sub-decode OP
assign aluop = ins[12:9];
assign aluop_x2y = ins[6];
assign aluop_sd = ins[5:4];
assign aluop_ext = ins[7];
// sub-decode OP.CMP
assign cmp_i = ins[2];
assign cmp_e = ins[1];
assign cmp_l = ins[0];
assign x_is_zero = X == {WIDTH{1'b0}};
// decode extended instructions
assign ins_reg = (ins_ext && ins[12:10] == 3'b000);
assign ins_mem = (ins_ext && ins[12:10] == 3'b001);
assign ins_loadi = (ins_mem && ins[9] == 1'b0);
assign ins_storei = (ins_mem && ins[9] == 1'b1);
assign ins_fpadj = (ins_ext && ins[12:10] == 3'b011);
assign ins_loadrel= (ins_ext && ins[12:10] == 3'b101);
// sub-decode LOADREG/STOREREG
assign ins_loadreg = (ins_reg && ins[9] == 1'b0);
assign ins_storereg = (ins_reg && ins[9] == 1'b1);
assign ins_reg_fp = (ins_reg && ins[3:0] == 4'b0000);
assign ins_reg_bp = (ins_reg && ins[3:0] == 4'b0001);
assign ins_reg_rp = (ins_reg && ins[3:0] == 4'b0010);
assign ins_reg_iv = (ins_reg && ins[3:0] == 4'b0011);
assign ins_reg_ir = (ins_reg && ins[3:0] == 4'b0100);
assign ins_reg_esp = (ins_reg && ins[3:0] == 4'b0101);
assign mem_read = ins_loadi || ins_load || ins_loadrel || (ins_xfer && xfer_r2p);
assign mem_write = ins_storei || ins_store || (ins_xfer && xfer_p2r);
assign mem_read_enable = (seq_state == FETCH) || (seq_state == EXEC && mem_read);
assign mem_write_enable = (seq_state == MEM && mem_write);
initial
begin
PC <= 0; nPC <= 0; seq_state <= MEM;
ESP <= -1; nESP <= -1;
addr <= 0;
FP <= 0; BP <= 0; RP <= 0; nRP <= 0;
IV <= 0; IR <= 0;
irq_pending <= 0;
end
// instruction sequencer
always @(posedge clk)
begin
if(reset)
seq_state <= MEM;
else if(mem_wait == 1'b0)
case(seq_state)
FETCH: seq_state <= DECODE;
DECODE: seq_state <= EXEC;
EXEC: seq_state <= MEM;
MEM: seq_state <= FETCH;
default: seq_state <= FETCH;
endcase
end
// operand register
assign operand =
(ins_load || ins_store || ins_branch || ins_cbranch) ?
{ {(WIDTH-13){ins[12]}}, ins[12:1], 1'b0 }
: (ins_loadc) ? { {(WIDTH-13){ins[12]}}, ins[12:0] } // sign extend
: (ins_aluop || ins_mem) ?
{ {(WIDTH-4){1'b0}}, ins[3:0] }
: (ins_loadrel) ? { {(WIDTH-10){1'b0}}, ins[9:0] }
: (ins_fpadj) ? { {(WIDTH-10){ins[9]}}, ins[9:0] } // sign extend
: { {WIDTH{1'b0}} };
// program counter
always @(posedge clk)
begin
if(reset) nPC <= 0;
else
case(seq_state)
EXEC:
if(ins_xfer && xfer_x2p) nPC <= X;
else if(ins_branch || (ins_cbranch && (x_is_zero != cbranch_n))) nPC <= PC + operand;
else nPC <= pc_next_ins;
MEM:
if(ins_xfer && xfer_r2p) nPC <= data_in;
else if(irq_pending) nPC <= IV;
endcase
end
// return stack pointer
always @*
begin
if(seq_state == EXEC || seq_state == DECODE || seq_state == MEM)
begin
if (ins_xfer) nRP <= RP +
({ {(ADDR_WIDTH-3){xfer_rs[1]}},xfer_rs} << WORDSIZE_SHIFT);
// sign extend xfer_rs and multiply by word size
else if (ins_storereg && ins_reg_rp) nRP <= X;
else nRP <= RP;
end
else nRP <= nRP;
end
// instruction fetch
// depending on bit 1 of the PC, read either the upper or lower half word as an instruction
always @* if(seq_state == DECODE) ins <= PC[1] ? data_in[15:0] : data_in[31:16];
// RAM read/write
always @(posedge clk)
begin
if(reset)
begin
addr <= 0;
mem_write_data <= 0;
end
else
case(seq_state)
DECODE:
if(ins_load || ins_store) // read from address in BP/FP + offset
addr <= operand + ( loadstore_base ? BP: FP);
else if (ins_loadi) // read from address in X
addr <= X;
else if (ins_storei) // write to address in Y
addr <= Y;
else if (ins_loadrel) // read from address next to current instruction
addr <= PC + operand;
else if (ins_xfer && xfer_r2p) // read from return stack
addr <= RP; // use the current RP
else if (ins_xfer && xfer_p2r) // write to return stack
addr <= nRP; // use the new RP
EXEC:
begin
if (ins_store)
mem_write_data <= X;
else if (ins_storei)
mem_write_data <= X;
else if (ins_xfer && xfer_p2r)
mem_write_data <= pc_next_ins;
else
mem_write_data <= 0;
end
MEM:
if(!mem_wait) // do not change the address if mem_wait is active
begin
if(ins_xfer && xfer_r2p) addr <= data_in; // on RET take addr for next instruction from the data we just read from mem
else addr <= irq_pending ? IV : nPC; // prepare fetch cycle
end
endcase
end
// X/ToS-Register
always @(posedge clk)
begin
if(reset) nX <= 0;
else
case(seq_state)
// default: nX <= X;
FETCH, DECODE:;
EXEC:
if(ins_loadc) nX <= operand;
else if(ins_cbranch || ins_store || ins_storereg || (ins_xfer && xfer_x2p)) nX <= Y;
else if(ins_storei) nX <= Y + operand;
else if(ins_loadreg && ins_reg_fp) nX <= FP;
else if(ins_loadreg && ins_reg_bp) nX <= BP;
else if(ins_loadreg && ins_reg_rp) nX <= RP;
else if(ins_loadreg && ins_reg_iv) nX <= IV;
else if(ins_loadreg && ins_reg_ir) nX <= IR;
else if(ins_loadreg && ins_reg_esp) nX <= ESP;
else if(ins_aluop)
begin
case(aluop)
4'b0000: nX = X + Y; // ADD
4'b0001: nX = Y - X; // SUB
4'b0010: nX = ~X; // NOT
4'b0011: nX = X & Y; // AND
4'b0100: nX = X | Y; // OR
4'b0101: nX = X ^ Y; // XOR
4'b0110: nX = // CMP
cmp_i ^ ((cmp_e && x_equals_y) || (cmp_l && y_lessthan_x));
4'b0111: nX = Y; // Y
4'b1000: nX = aluop_ext ? X >>> 1 : X >> 1; // SHR
4'b1001: nX = operand[1] ? X << 2 : X << 1; // SHL
4'b1010: nX = X + operand; // INC
4'b1011: nX = X - operand; // DEC
4'b1100: nX = // CMPU
cmp_i ^ ((cmp_e && x_equals_y) || (cmp_l && yx_unsigned_less));
// 4'b1101: nX = X[7:0] << ((3 - Y[1:0]) << 3); // BPLC
4'b1101: nX = Y[1:0] == 0 ? { X[7:0], 24'b0 } :
Y[1:0] == 1 ? { 8'b0, X[7:0], 16'b0 } :
Y[1:0] == 2 ? { 16'b0, X[7:0], 8'b0 } :
{ 24'b0, X[7:0]}; // BPLC
4'b1110: nX = { X[23:16], X[15:8], X[7:0], X[31:24] }; // BROT
4'b1111: nX = { 24'b0, Y[1:0] == 0 ? X[31:24] : Y[1:0] == 1 ? X[23:16] :
Y[1:0] == 2 ? X[15: 8] : X[7:0] }; // BSEL
// 4'b1110: nX = X * Y; // MUL
// 4'b1111: nX = X / Y; // DIV
default: nX = X;
endcase
end
MEM:
if (ins_loadi || ins_load || ins_loadrel)
nX = data_in;
endcase
end
// estack movement
wire [EVAL_STACK_INDEX_WIDTH-1:0] delta =
((ins_load || ins_loadc || ins_loadreg || ins_loadrel)) ? 1
: ((ins_aluop || ins_loadi || ins_storei || ins_xfer)) ?
{ {(EVAL_STACK_INDEX_WIDTH-2){aluop_sd[1]}},aluop_sd} // sign extend
: ((ins_store || ins_cbranch || ins_xfer || ins_storereg)) ? -1
: 0;
always @*
begin
if(reset)
nESP <= 0;
else
if(seq_state == EXEC)
begin
nESP = ESP + delta;
end
end
always @(posedge clk)
begin
// when to write (old) X back to stack (new Y)
// stack write is a reg so it is 1 in the next cycle i.e. MEM state
stack_write <= (seq_state == EXEC &&
(ins_load || ins_loadc || ins_loadrel || ins_loadreg
|| ((ins_loadi || ins_storei || ins_aluop) && aluop_x2y)));
end
// FP register
always @(posedge clk)
begin
if(seq_state == EXEC)
begin
if(ins_fpadj) FP <= FP + operand;
else if(ins_storereg && ins_reg_fp) FP <= X;
end
end
// BP register
always @(posedge clk) if(seq_state == EXEC && ins_storereg && ins_reg_bp) BP <= X;
// IV register
always @(posedge clk)
begin
if(reset)
IV <= 0;
else if(seq_state == EXEC && ins_storereg && ins_reg_iv)
IV <= X;
end
// IR register
always @(posedge clk)
begin
if(seq_state == MEM && irq_pending) IR <= nPC; // use nPC as interrupt return addr
end
// process irq
always @(posedge clk)
begin
if(seq_state == MEM && irq_pending && !(ins_xfer & xfer_r2p)) // in FETCH state, clear irq_pending.
irq_pending <= 0;
else
irq_pending <= irq_pending || irq; // else set irq_pending when irq is high
end
// advance CPU state
always @ (posedge clk)
begin
if(reset)
{ PC, X, ESP, RP } <= { {WIDTH{1'b0}}, {WIDTH{1'b0}}, {WIDTH{1'b0}}, {WIDTH{1'b0}} };
else if(seq_state == FETCH)
{ PC, X, ESP, RP } <= { nPC, nX, nESP, nRP};
end
endmodule

54
rtl/src/testbench.v Normal file
View file

@ -0,0 +1,54 @@
`timescale 1ns/1ps
`default_nettype none
module testbench();
reg clk;
reg rst_n;
wire btn0;
wire sw0;
wire sw1;
wire led0;
wire led1;
wire led2;
wire led3;
wire uart_txd_in;
wire uart_rxd_out;
wire [15:0] ddr3_dq;
wire [1:0] ddr3_dqs_n;
wire [1:0] ddr3_dqs_p;
wire [13:0] ddr3_addr;
wire [2:0] ddr3_ba;
wire ddr3_ras_n;
wire ddr3_cas_n;
wire ddr3_we_n;
wire ddr3_reset_n;
wire [0:0] ddr3_ck_p;
wire [0:0] ddr3_ck_n;
wire [0:0] ddr3_cke;
wire [0:0] ddr3_cs_n;
wire [1:0] ddr3_dm;
wire [0:0] ddr3_odt;
integer t;
top top0(clk, rst_n, btn0, sw0,sw1, led0, led1, led2, led3, uart_txd_in, uart_rxd_out,
ddr3_dq, ddr3_dqs_n, ddr3_dqs_p, ddr3_addr, ddr3_ba, ddr3_ras_n, ddr3_cas_n,
ddr3_we_n, ddr3_reset_n, ddr3_ck_p, ddr3_ck_n, ddr3_cke, ddr3_cs_n, ddr3_dm, ddr3_odt);
initial begin
clk = 1;
t = 0;
rst_n = 0;
end
always #5.0 clk = ~clk;
always @(posedge clk) begin
t <= t + 1;
if (t == 2)
rst_n = 1;
if (t == 400)
$finish;
end
endmodule

288
rtl/src/top.v Normal file
View file

@ -0,0 +1,288 @@
`timescale 1ns / 1ps
// either define clock as clk (100MHz on Arty)
// or as clk_1hz for debugging
`define clock cpuclk
`define clkfreq 83333333
//`define clock clk
//`define clkfreq 100000000
//`define clock clk_1hz
`define ENABLE_VGAFB
`define ENABLE_MICROSD
module top(
input wire clk,
input wire rst,
input wire btn0,
input wire sw0,
input wire sw1,
output wire led0,
output wire led1,
output wire led2,
output wire led3,
input wire uart_txd_in,
output wire uart_rxd_out,
// DDR3 SDRAM
inout wire [15:0] ddr3_dq,
inout wire [1:0] ddr3_dqs_n,
inout wire [1:0] ddr3_dqs_p,
output wire [13:0] ddr3_addr,
output wire [2:0] ddr3_ba,
output wire ddr3_ras_n,
output wire ddr3_cas_n,
output wire ddr3_we_n,
output wire ddr3_reset_n,
output wire [0:0] ddr3_ck_p,
output wire [0:0] ddr3_ck_n,
output wire [0:0] ddr3_cke,
output wire [0:0] ddr3_cs_n,
output wire [1:0] ddr3_dm,
output wire [0:0] ddr3_odt
`ifdef ENABLE_VGAFB
,
output wire [3:0] VGA_R,
output wire [3:0] VGA_G,
output wire [3:0] VGA_B,
output wire VGA_HS_O,
output wire VGA_VS_O
`endif
`ifdef ENABLE_MICROSD
,
output wire sd_cs_n,
output wire sd_mosi,
input wire sd_miso,
output wire sd_sck,
input wire sd_cd
`endif
);
reg clk_1hz;
reg [31:0] counter;
localparam ADDR_WIDTH = 32, WIDTH = 32,
ROMADDR_WIDTH = 11, IOADDR_WIDTH = 11, IOADDR_SEL = 4;
wire [ADDR_WIDTH-1:0] mem_addr;
wire [WIDTH-1:0] mem_read_data;
wire [WIDTH-1:0] mem_write_data;
(* KEEP *) wire mem_wait;
(* KEEP *) wire mem_read_enable;
(* KEEP *) wire mem_write_enable;
(* KEEP *) wire io_enable;
wire [WIDTH-1:0] io_rd_data;
wire [IOADDR_SEL-1:0] io_slot = mem_addr[IOADDR_WIDTH-1:IOADDR_WIDTH-IOADDR_SEL];
wire irq;
// assign led0 = mem_wait;
wire [WIDTH-1:0] debug_data1, debug_data2,
debug_data3, debug_data4,
debug_data5, debug_data6;
assign led0 = debug_data6[0];
wire cpuclk, cpuclk_locked;
wire dram_refclk200;
wire pixclk;
cpu_clkgen cpuclk_0(~rst, clk, cpuclk, dram_refclk200, pixclk, cpuclk_locked);
// DRAM --------------------------------------------------------------------------
wire [ADDR_WIDTH-1:0] dram_addr;
wire [WIDTH-1:0] dram_read_data, dram_write_data;
wire dram_read_enable, dram_write_enable, dram_wait;
dram_bridge dram_bridge0 (dram_addr,
dram_read_data, dram_write_data, dram_read_enable, dram_write_enable, dram_wait,
rst, cpuclk, dram_refclk200,
ddr3_dq, ddr3_dqs_n, ddr3_dqs_p, ddr3_addr,
ddr3_ba, ddr3_ras_n, ddr3_cas_n, ddr3_we_n,
ddr3_reset_n, ddr3_ck_p, ddr3_ck_n, ddr3_cke,
ddr3_cs_n, ddr3_dm, ddr3_odt);
mem #(.ADDR_WIDTH(ADDR_WIDTH), .DATA_WIDTH(WIDTH)) mem0(
.clk(`clock), .rst_n(rst), .addr(mem_addr),
.data_out(mem_read_data), .read_enable(mem_read_enable),
.data_in(mem_write_data), .write_enable(mem_write_enable),
.io_enable(io_enable),
.io_rd_data(io_rd_data),
.mem_wait(mem_wait),
.dram_addr(dram_addr),
.dram_read_data(dram_read_data),
.dram_write_data(dram_write_data),
.dram_read_enable(dram_read_enable),
.dram_write_enable(dram_write_enable),
.dram_wait(dram_wait)
);
`ifdef ENABLE_VGAFB
localparam FB_ADDR_WIDTH = 14;
wire [FB_ADDR_WIDTH-1:0] fb_rd_addr;
wire [FB_ADDR_WIDTH-1:0] fb_wr_addr;
wire [WIDTH-1:0] fb_rd_data;
wire [WIDTH-1:0] fb_wr_data;
wire fb_rd_en, fb_wr_en;
wire fb_cs_en = io_enable && (io_slot == 2);
assign fb_rd_en = fb_cs_en && mem_read_enable;
assign fb_wr_en = fb_cs_en && mem_write_enable;
assign fb_wr_data = mem_write_data;
vgafb vgafb0(`clock, pixclk, rst,
mem_addr[3:0], fb_rd_data, fb_wr_data,
fb_rd_en, fb_wr_en,
VGA_HS_O, VGA_VS_O, VGA_R, VGA_G, VGA_B);
`endif
// SPI SD card controller -------------------------------------------------------------------
`ifdef ENABLE_MICROSD
wire [7:0] spi_tx_data;
(*KEEP*) wire [7:0] spi_rx_data;
wire spi_tx_ready; // ready to transmit new data
wire spi_tx_empty; // tx fifo is empty
wire spi_rx_avail; // a byte has been received
wire spi_rx_ovr; // receiver overrun
wire spi_tx_write; // write strobe
wire spi_rx_read; // read strobe (clears rx_avail)
wire spi_card_detect; // true is card is present
wire spi_card_changed; // card_detect signal has changed
wire spi_card_busy; // card is busy (MISO/DO is 0)
wire spi_ctrl_write; // set the following flags
wire spi_rx_filter_en; // set to wait for start bit (1-to-0) when receiving
wire spi_txrx_en; // enable transmitter and receiver
wire spi_sclk_f_en; // enable spi clock without transceiver
wire spi_sclk_div_wr; // set clock divider from tx_data
wire spi_cs; // cs signal for spi controller
wire [WIDTH-1:0] spi_rd_data;
assign spi_cs = io_enable && (io_slot == 1);
// spi read data: [ 0,...,0,cd,cc,cb,tr,te,ra,ro,d,d,d,d,d,d,d,d ]
// cd = card detect, cc = card changed, cb = card busy,
// tr = transmitter ready, te = tx fifo empty,
// ra = received byte available, ro = receive overrun, d = received byte
assign spi_rd_data =
{ {WIDTH-15{1'b0}}, spi_card_detect, spi_card_changed, spi_card_busy,
spi_tx_ready, spi_tx_empty,
spi_rx_avail, spi_rx_ovr, spi_rx_data };
// spi write data: [ 0,...,0,CW,CF,Cx,Cc,Cd,DR,DW,d,d,d,d,d,d,d,d ]
// CW = control write, CF = enable receive filter, Cx = enable transceiver,
// Cc = force spi clock on, Cd = write clock divider,
// DR = read acknowledge, DW = data write, d = byte to be sent
assign spi_ctrl_write = spi_cs && mem_write_enable && mem_write_data[14];
assign spi_rx_filter_en = mem_write_data[13];
assign spi_txrx_en = mem_write_data[12];
assign spi_sclk_f_en = mem_write_data[11];
assign spi_sclk_div_wr = spi_cs && mem_write_enable && mem_write_data[10];
assign spi_rx_read = mem_write_data[9];
assign spi_tx_write = spi_cs && mem_write_enable && mem_write_data[8];
assign spi_tx_data = mem_write_data[7:0];
sdspi sdspi0(.clk(`clock), .reset(~rst),
.tx_data(spi_tx_data), .rx_data(spi_rx_data),
.tx_ready(spi_tx_ready), .tx_empty(spi_tx_empty),
.rx_avail(spi_rx_avail), .rx_ovr(spi_rx_ovr),
.tx_write(spi_tx_write), .rx_read(spi_rx_read),
.card_detect(spi_card_detect), .card_changed(spi_card_changed), .card_busy(spi_card_busy),
// ctrl_write is used with rx_filter_en, txrx_en and spiclk_f_en
.ctrl_write(spi_ctrl_write),
.rx_filter_en(spi_rx_filter_en), .txrx_en(spi_txrx_en), .spiclk_f_en(spi_sclk_f_en),
//
.spiclk_div_wr(spi_sclk_div_wr),
.sd_cs_n(sd_cs_n),
.sd_mosi(sd_mosi), .sd_miso(sd_miso), .sd_sck(sd_sck), .sd_cd(sd_cd));
`endif
// UART -----------------------------------------------------------------------
// uart write data: [ 0, 0, 0, 0, 0, T, C, 0, c, c, c, c, c, c, c, c ]
// T = transmit enable, C = receiver clear, c = 8-bit-character
// uart read data: [ 0, 0, 0, 0, 0, 0, A, B, c, c, c, c, c, c, c, c ]
// A = char available, B = tx busy, c = 8-bit-character
wire uart_cs = io_enable && (io_slot == 0);
wire uart_tx_en = uart_cs && mem_write_enable && mem_write_data[10];
wire uart_rx_clear = uart_cs && mem_write_enable && mem_write_data[9];
wire uart_rx_avail;
wire uart_rx_busy, uart_tx_busy;
wire uart_err;
wire [7:0] uart_rx_data;
wire [7:0] uart_tx_data;
wire [31:0] uart_baud = 32'd115200;
wire [WIDTH-1:0] uart_rd_data;
assign uart_tx_data = mem_write_data[7:0];
assign uart_rd_data = { {WIDTH-10{1'b1}}, uart_rx_avail, uart_tx_busy, uart_rx_data };
reg timer_tick;
reg[23:0] tick_count;
wire [1:0] irq_in = { timer_tick, uart_rx_avail };
wire [1:0] irqc_rd_data0;
wire [WIDTH-1:0] irqc_rd_data = { tick_count, 6'b0, irqc_rd_data0 };
wire irqc_seten = mem_write_data[7];
wire irqc_cs = io_enable && (io_slot == 3);
assign io_rd_data = (io_slot == 0) ? uart_rd_data :
`ifdef ENABLE_MICROSD
(io_slot == 1) ? spi_rd_data :
`endif
`ifdef ENABLE_VGAFB
(io_slot == 2) ? fb_rd_data :
`endif
(io_slot == 3) ? irqc_rd_data:
-1;
buart #(.CLKFREQ(`clkfreq)) uart0(`clock, rst,
uart_baud,
uart_txd_in, uart_rxd_out,
uart_rx_clear, uart_tx_en,
uart_rx_avail, uart_tx_busy,
uart_tx_data, uart_rx_data);
// CPU -----------------------------------------------------------------
stackcpu cpu0(.clk(`clock), .rst(rst), .irq(irq),
.addr(mem_addr),
.data_in(mem_read_data), .read_enable(mem_read_enable),
.data_out(mem_write_data), .write_enable(mem_write_enable),
.mem_wait(mem_wait),
.led1(led1), .led2(led2), .led3(led3),
.debug_out1(debug_data1),
.debug_out2(debug_data2),
.debug_out3(debug_data3),
.debug_out4(debug_data4),
.debug_out5(debug_data5),
.debug_out6(debug_data6));
// Interrupt Controller
irqctrl irqctrl0(`clock, irq_in, irqc_cs, mem_write_enable,
irqc_seten, irqc_rd_data0,
irq);
// count clock ticks
// generate interrupt every 20nth of a second
always @ (posedge `clock)
begin
counter <= counter + 1;
if (counter >= (`clkfreq/20))
begin
counter <= 0;
timer_tick <= 1;
tick_count <= tick_count + 1'b1;
end
else
begin
timer_tick <= 0;
end
end
endmodule

262
rtl/src/uart.v Normal file
View file

@ -0,0 +1,262 @@
/*
Copyright (c) 2010-2020, James Bowman
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of swapforth nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
`default_nettype none
//`define def_clkfreq 100000000
`define def_clkfreq 83333333
module baudgen(
input wire clk,
input wire resetq,
input wire [31:0] baud,
input wire restart,
output wire ser_clk);
parameter CLKFREQ = `def_clkfreq;
wire [38:0] aclkfreq = CLKFREQ;
reg [38:0] d;
wire [38:0] dInc = d[38] ? ({4'd0, baud}) : (({4'd0, baud}) - aclkfreq);
wire [38:0] dN = restart ? 0 : (d + dInc);
wire fastclk = ~d[38];
assign ser_clk = fastclk;
always @(negedge resetq or posedge clk)
begin
if (!resetq) begin
d <= 0;
end else begin
d <= dN;
end
end
endmodule
/*
-----+ +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+----
| | | | | | | | | | | |
|start| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |stop1|stop2|
| | | | | | | | | | | ? |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+ +
*/
module uart(
input wire clk, // System clock
input wire resetq,
// Outputs
output wire uart_busy, // High means UART is transmitting
output reg uart_tx, // UART transmit wire
// Inputs
input wire [31:0] baud,
input wire uart_wr_i, // Raise to transmit byte
input wire [7:0] uart_dat_i // 8-bit data
);
parameter CLKFREQ = `def_clkfreq;
reg [3:0] bitcount;
reg [8:0] shifter;
assign uart_busy = |bitcount;
wire sending = |bitcount;
wire ser_clk;
wire starting = uart_wr_i & ~uart_busy;
baudgen #(.CLKFREQ(CLKFREQ)) _baudgen(
.clk(clk),
.resetq(resetq),
.baud(baud),
.restart(1'b0),
.ser_clk(ser_clk));
always @(negedge resetq or posedge clk)
begin
if (!resetq) begin
uart_tx <= 1;
bitcount <= 0;
shifter <= 0;
end else begin
if (starting) begin
shifter <= { uart_dat_i[7:0], 1'b0 };
bitcount <= 1 + 8 + 1;
end
if (sending & ser_clk) begin
{ shifter, uart_tx } <= { 1'b1, shifter };
bitcount <= bitcount - 4'd1;
end
end
end
endmodule
module rxuart(
input wire clk,
input wire resetq,
input wire [31:0] baud,
input wire uart_rx, // UART recv wire
input wire rd, // read strobe
output wire valid, // has data
output wire [7:0] data); // data
parameter CLKFREQ = `def_clkfreq;
reg [4:0] bitcount;
reg [7:0] shifter;
// On starting edge, wait 3 half-bits then sample, and sample every 2 bits thereafter
wire idle = &bitcount;
wire sample;
reg [2:0] hh = 3'b111;
wire [2:0] hhN = {hh[1:0], uart_rx};
wire startbit = idle & (hhN[2:1] == 2'b10);
wire [7:0] shifterN = sample ? {hh[1], shifter[7:1]} : shifter;
wire ser_clk;
baudgen #(.CLKFREQ(CLKFREQ)) _baudgen(
.clk(clk),
.baud({baud[30:0], 1'b0}),
.resetq(resetq),
.restart(startbit),
.ser_clk(ser_clk));
assign valid = (bitcount == 18);
reg [4:0] bitcountN;
always @*
if (startbit)
bitcountN = 0;
else if (!idle & !valid & ser_clk)
bitcountN = bitcount + 5'd1;
else if (valid & rd)
bitcountN = 5'b11111;
else
bitcountN = bitcount;
// 3,5,7,9,11,13,15,17
assign sample = (bitcount > 2) & bitcount[0] & !valid & ser_clk;
assign data = shifter;
always @(negedge resetq or posedge clk)
begin
if (!resetq) begin
hh <= 3'b111;
bitcount <= 5'b11111;
shifter <= 0;
end else begin
hh <= hhN;
bitcount <= bitcountN;
shifter <= shifterN;
end
end
endmodule
module fifo_rxuart(
input wire clk,
input wire resetq,
input wire [31:0] baud,
input wire uart_rx, // UART recv wire
input wire rd, // read strobe
output wire valid, // has data
output wire [7:0] data); // data
parameter CLKFREQ = `def_clkfreq;
localparam ADDR_WIDTH = 6;
localparam DATA_WIDTH = 8;
reg fifo_wr_en;
(*KEEP*) wire fifo_rd_en, fifo_full, fifo_empty;
wire [DATA_WIDTH-1:0] fifo_wr_data, fifo_rd_data;
(*KEEP*) wire rx_avail;
assign valid = !fifo_empty;
assign data = fifo_rd_data;
assign fifo_rd_en = rd;
fifo #(.ADDR_WIDTH(ADDR_WIDTH)) rx_fifo(clk, ~resetq,
fifo_wr_en, fifo_rd_en,
fifo_wr_data, fifo_rd_data,
fifo_full,
fifo_empty
);
rxuart #(.CLKFREQ(CLKFREQ)) _rx (
.clk(clk),
.resetq(resetq),
.baud(baud),
.uart_rx(uart_rx),
.rd(fifo_wr_en), // strobe read signal on fifo write
.valid(rx_avail),
.data(fifo_wr_data));
always @(posedge clk)
begin
if (!resetq)
fifo_wr_en <= 0;
else if(!fifo_wr_en && rx_avail) // ILA shows fifo_wr_en stays 0 ??
fifo_wr_en <= 1; // pulse fifo_wr_en for one clock
else // rx_avail goes zero one clock later
fifo_wr_en <= 0;
end
endmodule
module buart(
input wire clk,
input wire resetq,
input wire [31:0] baud,
input wire rx, // recv wire
output wire tx, // xmit wire
input wire rd, // read strobe
input wire wr, // write strobe
output wire valid, // has recv data
output wire busy, // is transmitting
input wire [7:0] tx_data,
output wire [7:0] rx_data // data
);
parameter CLKFREQ = `def_clkfreq;
fifo_rxuart #(.CLKFREQ(CLKFREQ)) _rx (
.clk(clk),
.resetq(resetq),
.baud(baud),
.uart_rx(rx),
.rd(rd),
.valid(valid),
.data(rx_data));
uart #(.CLKFREQ(CLKFREQ)) _tx (
.clk(clk),
.resetq(resetq),
.baud(baud),
.uart_busy(busy),
.uart_tx(tx),
.uart_wr_i(wr),
.uart_dat_i(tx_data));
endmodule

100
rtl/src/uart_tb.v Normal file
View file

@ -0,0 +1,100 @@
//////////////////////////////////////////////////////////////////////
// File Downloaded from http://www.nandland.com
//////////////////////////////////////////////////////////////////////
// This testbench will exercise both the UART Tx and Rx.
// It sends out byte 0xAB over the transmitter
// It then exercises the receive by receiving byte 0x3F
`timescale 1ns/10ps
module uart_tb ();
// Testbench uses a 10 MHz clock
// Want to interface to 115200 baud UART
// 10000000 / 115200 = 87 Clocks Per Bit.
parameter c_CLOCK_PERIOD_NS = 100;
parameter c_CLKS_PER_BIT = 87;
parameter c_BIT_PERIOD = 8600;
reg r_Clock = 0;
reg r_Tx_DV = 0;
wire w_Tx_Done;
reg [7:0] r_Tx_Byte = 0;
reg r_Rx_Serial = 1;
wire [7:0] w_Rx_Byte;
// Takes in input byte and serializes it
task UART_WRITE_BYTE;
input [7:0] i_Data;
integer ii;
begin
// Send Start Bit
r_Rx_Serial <= 1'b0;
#(c_BIT_PERIOD);
#1000;
// Send Data Byte
for (ii=0; ii<8; ii=ii+1)
begin
r_Rx_Serial <= i_Data[ii];
#(c_BIT_PERIOD);
end
// Send Stop Bit
r_Rx_Serial <= 1'b1;
#(c_BIT_PERIOD);
end
endtask // UART_WRITE_BYTE
uart_rx #(.CLKS_PER_BIT(c_CLKS_PER_BIT)) UART_RX_INST
(.i_Clock(r_Clock),
.i_Rx_Serial(r_Rx_Serial),
.o_Rx_DV(),
.o_Rx_Byte(w_Rx_Byte)
);
uart_tx #(.CLKS_PER_BIT(c_CLKS_PER_BIT)) UART_TX_INST
(.i_Clock(r_Clock),
.i_Tx_DV(r_Tx_DV),
.i_Tx_Byte(r_Tx_Byte),
.o_Tx_Active(),
.o_Tx_Serial(),
.o_Tx_Done(w_Tx_Done)
);
always
#(c_CLOCK_PERIOD_NS/2) r_Clock <= !r_Clock;
// Main Testing:
initial
begin
// Tell UART to send a command (exercise Tx)
@(posedge r_Clock);
@(posedge r_Clock);
r_Tx_DV <= 1'b1;
r_Tx_Byte <= 8'hAB;
@(posedge r_Clock);
r_Tx_DV <= 1'b0;
@(posedge w_Tx_Done);
// Send a command to the UART (exercise Rx)
@(posedge r_Clock);
UART_WRITE_BYTE(8'h3F);
@(posedge r_Clock);
// Check that the correct command was received
if (w_Rx_Byte == 8'h3F)
$display("Test Passed - Correct Byte Received");
else
$display("Test Failed - Incorrect Byte Received");
end
endmodule

292
rtl/src/vgafb.v Normal file
View file

@ -0,0 +1,292 @@
`timescale 1ns / 1ps
`default_nettype none
// Project F: Display Timings
// (C)2019 Will Green, Open Source Hardware released under the MIT License
// Learn more at https://projectf.io
//128K video memory is not enough for 640x480x4
`define RES_640_400
//`define RES_1024_768
module display_timings #(
H_RES=640, // horizontal resolution (pixels)
V_RES=480, // vertical resolution (lines)
H_FP=16, // horizontal front porch
H_SYNC=96, // horizontal sync
H_BP=48, // horizontal back porch
V_FP=10, // vertical front porch
V_SYNC=2, // vertical sync
V_BP=33, // vertical back porch
H_POL=0, // horizontal sync polarity (0:neg, 1:pos)
V_POL=0 // vertical sync polarity (0:neg, 1:pos)
)
(
input wire i_pix_clk, // pixel clock
input wire i_rst, // reset: restarts frame (active high)
output wire o_hs, // horizontal sync
output wire o_vs, // vertical sync
output wire o_de, // display enable: high during active video
output wire o_frame, // high for one tick at the start of each frame
output wire o_scanline, // high for one tick at the start of each scanline
output reg o_vblank, // high during vertical blank phase
output reg signed [15:0] o_sx, // horizontal beam position (including blanking)
output reg signed [15:0] o_sy // vertical beam position (including blanking)
);
// Horizontal: sync, active, and pixels
localparam signed H_STA = 0 - H_FP - H_SYNC - H_BP; // horizontal start
localparam signed HS_STA = H_STA + H_FP; // sync start
localparam signed HS_END = HS_STA + H_SYNC; // sync end
localparam signed HA_STA = 0; // active start
localparam signed HA_END = H_RES - 1; // active end
// Vertical: sync, active, and pixels
localparam signed V_STA = 0 - V_FP - V_SYNC - V_BP; // vertical start
localparam signed VS_STA = V_STA + V_FP; // sync start
localparam signed VS_END = VS_STA + V_SYNC; // sync end
localparam signed VA_STA = 0; // active start
localparam signed VA_END = V_RES - 1; // active end
// generate sync signals with correct polarity
assign o_hs = H_POL ? (o_sx > HS_STA && o_sx <= HS_END)
: ~(o_sx > HS_STA && o_sx <= HS_END);
assign o_vs = V_POL ? (o_sy > VS_STA && o_sy <= VS_END)
: ~(o_sy > VS_STA && o_sy <= VS_END);
// display enable: high during active period
assign o_de = (o_sx >= 0 && o_sy >= 0);
// o_frame: high for one tick at the start of each frame
assign o_frame = (o_sy == V_STA && o_sx == H_STA);
// o_scanline: high for one tick at the start of each visible scanline
assign o_scanline = (o_sy >= VA_STA) && (o_sy <= VA_END) && (o_sx == H_STA);
always @(posedge i_pix_clk)
begin
if(o_frame) o_vblank <= 1;
else if (o_de) o_vblank <= 0;
end
always @ (posedge i_pix_clk)
begin
if (i_rst) // reset to start of frame
begin
o_sx <= H_STA;
o_sy <= V_STA;
end
else
begin
if (o_sx == HA_END) // end of line
begin
o_sx <= H_STA;
if (o_sy == VA_END) // end of frame
o_sy <= V_STA;
else
o_sy <= o_sy + 16'sh1;
end
else
o_sx <= o_sx + 16'sh1;
end
end
endmodule
// Project F: Display Controller VGA Demo
// (C)2020 Will Green, Open source hardware released under the MIT License
// Learn more at https://projectf.io
// This demo requires the following Verilog modules:
// * display_clocks
// * display_timings
// * test_card_simple or another test card
module vgafb #(VMEM_ADDR_WIDTH = 15, VMEM_DATA_WIDTH = 32) (
input wire cpu_clk, // cpu clock
input wire CLK, // pixel clock
input wire RST_BTN, // reset button
input wire[3:0] reg_sel, // register select/address
output wire [VMEM_DATA_WIDTH-1:0] rd_data,
input wire [VMEM_DATA_WIDTH-1:0] wr_data,
input wire rd_en,
input wire wr_en,
output wire VGA_HS, // horizontal sync output
output wire VGA_VS, // vertical sync output
output wire [3:0] VGA_R, // 4-bit VGA red output
output wire [3:0] VGA_G, // 4-bit VGA green output
output wire [3:0] VGA_B // 4-bit VGA blue output
);
localparam BITS_PER_PIXEL = 4; localparam MAX_SHIFT_COUNT = 7;
localparam REG_RD_ADDR = 0; localparam REG_WR_ADDR = 1; localparam REG_VMEM = 2;
localparam REG_PAL_SLOT = 3; localparam REG_PAL_DATA = 4;
localparam REG_CTL = 5;
localparam COLOR_WIDTH = 12;
localparam PALETTE_WIDTH = 4;
// Display Clocks
wire pix_clk = CLK; // pixel clock
wire clk_lock = 1; // clock locked?
wire vmem_rd_en;
wire vmem_wr_en;
wire [VMEM_DATA_WIDTH-1:0] vmem_rd_data;
reg [VMEM_ADDR_WIDTH-1:0] cpu_rd_addr;
reg [VMEM_ADDR_WIDTH-1:0] cpu_wr_addr;
reg [VMEM_ADDR_WIDTH-1:0] pix_addr;
wire [VMEM_DATA_WIDTH-1:0] pix_data;
wire pix_rd;
wire [VMEM_DATA_WIDTH-1:0] status;
assign vmem_rd_en = rd_en;
assign vmem_wr_en = (reg_sel == REG_VMEM) && wr_en;
assign rd_data = (reg_sel == REG_VMEM) ? vmem_rd_data :
(reg_sel == REG_RD_ADDR) ? cpu_rd_addr :
(reg_sel == REG_WR_ADDR) ? cpu_wr_addr :
(reg_sel == REG_CTL) ? status :
32'hFFFFFFFF;
wire [VMEM_ADDR_WIDTH-1:0] cpu_addr = vmem_wr_en ? cpu_wr_addr : cpu_rd_addr;
bram_tdp #(.DATA(VMEM_DATA_WIDTH),.ADDR(VMEM_ADDR_WIDTH)) vram0 (
.a_rd(vmem_rd_en), .a_clk(cpu_clk),
.a_wr(vmem_wr_en), .a_addr(cpu_addr), .a_din(wr_data),
.a_dout(vmem_rd_data),
.b_clk(pix_clk), .b_addr(pix_addr), .b_dout(pix_data),
.b_rd(pix_rd)
);
wire palette_wr_en = (reg_sel == REG_PAL_DATA) && wr_en;
reg [PALETTE_WIDTH-1:0] palette_wr_slot;
wire [COLOR_WIDTH-1:0] color_data;
palette palette0(.wr_clk(cpu_clk), .rd_clk(pix_clk), .wr_en(palette_wr_en),
.wr_slot(palette_wr_slot), .wr_data(wr_data[COLOR_WIDTH-1:0]),
.rd_slot(pixel[3:0]), .rd_data(color_data));
// Display Timings
wire signed [15:0] sx; // horizontal screen position (signed)
wire signed [15:0] sy; // vertical screen position (signed)
wire h_sync; // horizontal sync
wire v_sync; // vertical sync
wire de; // display enable
wire frame; // frame start
wire scanline; // scanline start
wire vblank; // vertical blank
reg vblank_buf; // vertical blank in cpu clock domain
display_timings #( // 640x480 800x600 1280x720 1920x1080
`ifdef RES_1024_768
.H_RES(1024), // 640 800 1280 1920
.V_RES(768), // 480 600 720 1080
.H_FP(24), // 16 40 110 88
.H_SYNC(136), // 96 128 40 44
.H_BP(160), // 48 88 220 148
.V_FP(3), // 10 1 5 4
.V_SYNC(6), // 2 4 5 5
.V_BP(29), // 33 23 20 36
.H_POL(0), // 0 1 1 1
.V_POL(0) // 0 1 1 1
`endif
`ifdef RES_640_400
.H_RES(640),
.V_RES(400),
.H_FP(16),
.H_SYNC(96),
.H_BP(48),
.V_FP(12),
.V_SYNC(2),
.V_BP(35),
.H_POL(0),
.V_POL(1)
`endif
)
display_timings_inst (
.i_pix_clk(CLK),
.i_rst(!RST_BTN),
.o_hs(h_sync),
.o_vs(v_sync),
.o_de(de),
.o_frame(frame),
.o_scanline(scanline),
.o_vblank(vblank),
.o_sx(sx),
.o_sy(sy)
);
wire [7:0] red;
wire [7:0] green;
wire [7:0] blue;
reg [VMEM_DATA_WIDTH-1:0] shifter;
reg [4:0] shift_count;
// delayed frame signal for pix_rd
reg frame_d;
assign pix_rd = frame_d || scanline || (shift_count == 2);
assign status = { 4'b0001, {(VMEM_DATA_WIDTH-5){1'b0}}, vblank_buf};
wire [BITS_PER_PIXEL-1:0] pixel = shifter[VMEM_DATA_WIDTH-1:VMEM_DATA_WIDTH-BITS_PER_PIXEL];
always @(posedge pix_clk) frame_d <= frame;
always @(posedge cpu_clk) vblank_buf <= vblank;
always @(posedge cpu_clk)
begin
if(wr_en)
begin
case(reg_sel)
REG_RD_ADDR: cpu_rd_addr <= wr_data;
REG_WR_ADDR: cpu_wr_addr <= wr_data;
REG_VMEM: cpu_wr_addr <= cpu_wr_addr + 1; // auto-increment write addr on write
REG_PAL_SLOT: palette_wr_slot <= wr_data[3:0];
endcase
end
else
if(rd_en && reg_sel == REG_VMEM) cpu_rd_addr <= cpu_rd_addr + 1; // auto-increment read addr on read
end
always @(posedge pix_clk)
begin
if(scanline || shift_count == MAX_SHIFT_COUNT) // before start of a line
begin // or at the end of a word, reset shifter with pixel data
shift_count <= 0;
shifter <= pix_data;
end
else if(de)
begin
shift_count <= shift_count + 1;
shifter <= shifter << BITS_PER_PIXEL;
end
if(frame) // at start of frame, reset pixel pointer
pix_addr <= 0;
else if(shift_count == 1) // after the first pixel, increment address
pix_addr <= pix_addr + 1;
end
// Hard-Coded RGBI palette
// // Pixel = { red, green, blue, intensity }
// assign red = pixel[3] ? pixel[0] ? 255 : 127: 0;
// assign green = pixel[2] ? pixel[0] ? 255 : 127: 0;
// assign blue = pixel[1] ? pixel[0] ? 255 : 127: 0;
// // VGA Output
// // VGA Pmod is 12-bit so we take the upper nibble of each colour
// assign VGA_HS = h_sync;
// assign VGA_VS = v_sync;
// assign VGA_R = de ? red[7:4] : 4'b0;
// assign VGA_G = de ? green[7:4] : 4'b0;
// assign VGA_B = de ? blue[7:4] : 4'b0;
// 12 bit RGB palette
assign VGA_HS = h_sync;
assign VGA_VS = v_sync;
assign VGA_R = de ? color_data[11:8] : 4'b0;
assign VGA_G = de ? color_data[7:4] : 4'b0;
assign VGA_B = de ? color_data[3:0] : 4'b0;
endmodule

View file

@ -23,7 +23,7 @@ On the first run, this may take a while as the go build system fetches some exte
Start the *tridoraemu* binary in the same directory as the SD-Card image file (*sdcard.img*) and the ROM file (*rommon.prog*). It needs to be started on the command line as it uses the terminal window for the serial console. On startup, the emulator opens the VGA framebuffer window which is only used for graphics output. Start the *tridoraemu* binary in the same directory as the SD-Card image file (*sdcard.img*) and the ROM file (*rommon.prog*). It needs to be started on the command line as it uses the terminal window for the serial console. On startup, the emulator opens the VGA framebuffer window which is only used for graphics output.
The Tridora software (esp. the editor) requires a decent vt100-compatible (plus colors) terminal emulator. It has been successfully tested with (new) Windows Terminal, WezTerm and xterm. The Tridora software (esp. the editor) requires a decent vt100-compatible (plus colors) terminal emulator. It has been successfully tested with (new) Windows Terminal, Alacritty, WezTerm and xterm.
The color scheme in the editor is meant for a dark terminal background. The color scheme in the editor is meant for a dark terminal background.