URL
https://opencores.org/ocsvn/xulalx25soc/xulalx25soc/trunk
Subversion Repositories xulalx25soc
Compare Revisions
- This comparison shows the changes necessary to convert path
/xulalx25soc
- from Rev 3 to Rev 4
- ↔ Reverse comparison
Rev 3 → Rev 4
/trunk/bench/asm/memtest.S
0,0 → 1,162
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: memtest.S |
// |
// Project: XuLA2 board |
// |
// Purpose: To test whether or not we can interface with the SDRAM on the |
// XuLA2 board. |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
#define LFSRFILL 0x000001 |
// #define LFSRTAPS 0x004597f |
#define LFSRTAPS 0x0408b85 |
#define SDRAMBASE 0x0800000 |
// #define SDRAMLEN 0x0800000 |
#define SDRAMLEN 0x0800000 |
#define RAMSCOPE 0x011c |
#define ZIPSCOPE 0x011e |
master_entry: |
MOV user_entry(PC),uPC |
; LDI RAMSCOPE,R8 |
; LDI 0x04000000,R9 |
; STO R9,(R8) |
RTU |
; // Capture what just happened |
; LDI 0x8c000000,R9 |
; STO R9,(R8) |
; NOP |
; |
HALT |
|
user_entry: |
// #define CLEAR_MEMORY |
#ifdef CLEAR_MEMORY |
clear_memory: |
LDI SDRAMBASE,R0 |
LDI SDRAMLEN,R1 |
ADD R0,R1 |
CLR R2 |
clear_memory_loop: |
STO R2,(R0) |
ADD 1,R0 |
CMP R0,R1 |
BGT clear_memory_loop |
end_clear_memory: |
#endif |
|
LDI LFSRFILL,R2 |
LDI LFSRTAPS,R3 |
CLR R12 |
|
write_test: |
LDI SDRAMBASE,R0 |
LDI SDRAMLEN,R1 |
MOV R2,R7 ; Copy our initial fill |
CMP 0,R2 |
HALT.Z |
// #define WAIT_FOR_WRITE_SCOPE |
#ifdef WAIT_FOR_WRITE_SCOPE |
LDI RAMSCOPE,R8 |
LDI 0x01ffc,R9 |
STO R9,(R8) ; Reset the SDRAM scope |
NOP ; Give it a chance to reset |
LDI 0x10000000,R10 |
scope_not_ready: |
NOP |
LOD (R8),R9 |
TST R10,R9 |
BZ scope_not_ready |
#endif |
|
write_test_loop: |
LSR 1,R2 |
XOR.C R3,R2 |
MOV R2,R4 |
|
LSR 1,R2 |
XOR.C R3,R2 |
MOV R2,R5 |
|
LSR 1,R2 |
XOR.C R3,R2 ; wr_reg_ce = R2 |
|
STO R4,(R0) ; op = R4 |
STO R5,1(R0) ; dcdA = R5 |
STO R2,2(R0) ; instruction - R2 |
ADD 3,R0 |
SUB 3,R1 |
CMP 3,R1 |
BGE write_test_loop |
|
read_test: |
LDI SDRAMBASE,R0 |
LDI SDRAMLEN,R1 |
// #define WAIT_FOR_READ_SCOPE |
#ifdef WAIT_FOR_READ_SCOPE |
LDI RAMSCOPE,R8 |
LDI 0x01ffc,R9 |
STO R9,(R8) ; Reset the SDRAM scope |
NOP ; Give it a chance to reset |
LDI 0x10000000,R10 |
not_ready: |
NOP |
LOD (R8),R9 |
TST R10,R9 |
BZ not_ready |
#endif |
// |
// RAM[49072] = 0x02b39ba ... not RAM[0]. What's going on here? |
// |
read_test_loop: |
LOD (R0),R4 |
LOD 1(R0),R5 |
LOD 2(R0),R6 |
|
LSR 1,R7 |
XOR.C R3,R7 |
CMP R7,R4 |
TRAP.NZ 0 |
|
LSR 1,R7 |
XOR.C R3,R7 |
CMP R7,R5 |
TRAP.NZ 0 |
|
LSR 1,R7 |
XOR.C R3,R7 |
CMP R7,R6 |
TRAP.NZ 0 |
|
ADD 3,R0 |
SUB 3,R1 |
CMP 3,R1 |
|
BGE read_test_loop |
|
ADD 1,R12 |
BRA write_test |
/trunk/bench/asm/dev.i
0,0 → 1,21
dev.base equ 0x0100 |
dev.version equ 2 |
dev.pic equ 3 |
dev.buserr equ 4 |
dev.rtc.date equ 5 |
dev.gpio equ 6 |
dev.uart.ctrl equ 7 |
dev.pwm equ 8 |
dev.uart.rx equ 10 |
dev.uart.tx equ 11 |
dev.qspi equ 12 |
dev.rtc.clock equ 16 |
dev.rtc.timer equ 17 |
dev.rtc.stopwatch equ 18 |
dev.rtc.alarm equ 19 |
dev.fscope equ 0x01c |
dev.ramscope equ 0x01e |
dev.mem.base equ 0x0002000 |
dev.mem.last equ 0x0003fff |
dev.flash.base equ 0x0040000 |
dev.sdram.base equ 0x0800000 |
/trunk/bench/asm/genlrs.S
0,0 → 1,72
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: genlrs.S |
// |
// Project: XuLA2 board |
// |
// Purpose: |
// |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
entry: |
; ; R0 -- used by test_lrs |
; ; R1 -- used by test_lrs |
; ; R2 -- used by test_lrs |
; ; R3 = return address |
LDI 0x80000000,R4 ; Taps |
LDI 0x00800000,R6 ; Current Memory Address |
MOV R6,R7 ; Start of memory |
LDI 0x00ffffff,R8 ; End of memory |
|
test_next_lrs: |
MOV __HERE__+2(PC),R3 |
BRA test_lrs |
CMP 0,R0 |
BGE next_tap_set |
STO R0,(R6) |
ADD 1,R6 |
AND R8,R6 |
OR R7,R6 |
next_tap_set: |
ADD 1,R4 |
BNZ test_next_lrs |
HALT |
|
test_lrs: |
; R0 = taps on entry |
; R0 = length on return |
; R3 = return PC address |
CLR R1 ; R1 will be our length |
LDI 1,R2 ; R2 will be our fill |
test_lrs_loop: |
LSR 1,R2 |
XOR.C R0,R2 |
ADD 1,R1 |
CMP 1,R2 |
BNZ test_lrs_loop |
MOV R1,R0 |
|
MOV R3,PC |
/trunk/bench/asm/Makefile
0,0 → 1,62
################################################################################ |
## |
## Filename: Makefile |
## |
## Project: XuLA2 board |
## |
## Purpose: |
## |
## |
## Creator: Dan Gisselquist, Ph.D. |
## Gisselquist Technology, LLC |
## |
################################################################################ |
## |
## Copyright (C) 2015, Gisselquist Technology, LLC |
## |
## This program is free software (firmware): you can redistribute it and/or |
## modify it under the terms of the GNU General Public License as published |
## by the Free Software Foundation, either version 3 of the License, or (at |
## your option) any later version. |
## |
## This program is distributed in the hope that it will be useful, but WITHOUT |
## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
## for more details. |
## |
## License: GPL, v3, as defined and found on www.gnu.org, |
## http:##www.gnu.org/licenses/gpl.html |
## |
## |
################################################################################ |
## |
## |
all: memtest.z |
ZIPD := $(HOME)/work/rnd/zipcpu/trunk |
ZASM := $(ZIPD)/sw/zasm/zasm |
ZDUMP:= $(ZIPD)/sw/zasm/zdump |
|
.PHONY: genlrs |
genlrs: genlrs.z |
genlrs.z: genlrs.S |
$(ZASM) $< -o $@ |
genlrs.txt: genlrs.z |
$(ZDUMP) $< > $@ |
|
.PHONY: cputest |
cputest: cputest.z |
cputest.z: cputest.S sys.i |
$(ZASM) $< -o $@ |
cputest.txt: cputest.z |
$(ZDUMP) $< > $@ |
|
.PHONY: memtest |
memtest: memtest.z |
memtest.z: memtest.S |
$(ZASM) $< -o $@ |
memtest.txt: memtest.z |
$(ZDUMP) $< > $@ |
|
.PHONY: |
clean: |
@rm memtest.z memtest.txt |
/trunk/bench/cpp/sdramsim.cpp
0,0 → 1,226
#include <stdio.h> |
#include <stdlib.h> |
#include <assert.h> |
|
#include "sdramsim.h" |
|
short SDRAMSIM::operator()(int clk, int cke, int cs_n, int ras_n, int cas_n, int we_n, |
int bs, unsigned addr, int driv, short data) { |
short result = 0; |
|
if (driv) |
result = data; |
else if (!clk) |
return m_last_value; |
if (!cke) { |
fprintf(stderr, "This simulation only supports CKE high!\n"); |
fprintf(stderr, "\tCKE = %d\n", cke); |
fprintf(stderr, "\tCS_n = %d\n", cs_n); |
fprintf(stderr, "\tRAS_n = %d\n", ras_n); |
fprintf(stderr, "\tCAS_n = %d\n", cas_n); |
fprintf(stderr, "\tWE_n = %d\n", we_n); |
assert(cke); |
} |
|
if (m_pwrup < POWERED_UP_STATE) { |
if (m_clocks_till_idle > 0) |
m_clocks_till_idle--; |
if (m_pwrup == 0) { |
assert((ras_n)&&(cas_n)&&(we_n)); |
if (m_clocks_till_idle == 0) { |
m_pwrup++; |
printf("Successful power up wait, moving to state #1\n"); |
} |
} else if (m_pwrup == 1) { |
if ((!cs_n)&&(!ras_n)&&(cas_n)&&(!we_n)&&(addr&0x0400)) { |
// Wait until a precharge all banks command |
m_pwrup++; |
printf("Successful precharge command, moving to state #2\n"); |
m_clocks_till_idle = 8; |
} |
} else if (m_pwrup == 2) { |
// Need 8 auto refresh cycles before or after the mode |
// set command. We'll insist they be before. |
if (m_clocks_till_idle == 0) { |
m_pwrup++; |
printf("Successful initial auto-refresh, waiting for mode-set\n"); |
for(int i=0; i<m_nrefresh; i++) |
m_refresh_time[i] = MAX_REFRESH_TIME; |
} else |
assert((!cs_n)&&(!ras_n)&&(!cas_n)&&(we_n)); |
} else if (m_pwrup == 3) { |
const int tRSC = 2; |
if ((!cs_n)&&(!ras_n)&&(!cas_n)&&(!we_n)){ |
// mode set |
printf("Mode set: %08x\n", addr); |
assert(addr == 0x021); |
m_pwrup++; |
printf("Successful mode set, moving to state #3, tRSC = %d\n", tRSC); |
m_clocks_till_idle=tRSC; |
} |
} else if (m_pwrup == 4) { |
assert(cs_n); |
if (m_clocks_till_idle == 0) { |
m_pwrup = POWERED_UP_STATE; |
m_clocks_till_idle = 0; |
printf("Successful settup! SDRAM switching to operational\n"); |
} else if (m_clocks_till_idle == 1) { |
; |
} else assert(0 && "Should never get here!"); |
} else if (m_pwrup == 5) { |
if ((!cs_n)&&(!ras_n)&&(!cas_n)&&(we_n)) { |
if (m_clocks_till_idle == 0) { |
m_pwrup = POWERED_UP_STATE; |
m_clocks_till_idle = 0; |
|
for(int i=0; i<m_nrefresh; i++) |
m_refresh_time[i] = MAX_REFRESH_TIME; |
} |
} else { |
assert(0); |
} |
} |
m_next_wr = false; |
} else { // In operation ... |
for(int i=0; i<m_nrefresh; i++) |
m_refresh_time[i]--; |
if (m_refresh_time[m_refresh_loc] < 0) { |
assert(0 && "Failed refresh requirement"); |
} for(int i=0; i<NBANKS; i++) { |
m_bank_status[i] >>= 1; |
if (m_bank_status[i]&2) |
m_bank_status[i] |= 4; |
if (m_bank_status[i]&1) { // Bank is open |
m_bank_open_time[i] --; |
if (m_bank_open_time[i] < 0) { |
assert(0 && "Bank held open too long"); |
} |
} |
} |
|
if (m_clocks_till_idle) |
m_clocks_till_idle--; |
|
if (m_fail > 0) { |
m_fail--; |
if (m_fail == 0) { |
fprintf(stderr, "Failing on schedule\n"); |
exit(-3); |
} |
} |
|
if ((m_clocks_till_idle > 0)&&(m_next_wr)) { |
printf("SDRAM[%08x] <= %04x\n", m_wr_addr, data & 0x0ffff); |
m_mem[m_wr_addr++] = data; |
result = data; |
m_next_wr = false; |
} else { |
result = (driv)?data:m_qdata[m_qloc]; |
} |
m_qloc = (m_qloc + 1)&m_qmask; |
|
if ((!cs_n)&&(!ras_n)&&(!cas_n)&&(we_n)) { |
// Auto-refresh command |
m_refresh_time[m_refresh_loc] = MAX_REFRESH_TIME; |
m_refresh_loc++; |
if (m_refresh_loc >= m_nrefresh) |
m_refresh_loc = 0; |
assert((m_bank_status[0]&6) == 0); |
assert((m_bank_status[1]&6) == 0); |
assert((m_bank_status[2]&6) == 0); |
assert((m_bank_status[3]&6) == 0); |
} else if ((!cs_n)&&(!ras_n)&&(cas_n)&&(!we_n)) { |
if (addr&0x0400) { |
// Bank/Precharge All CMD |
for(int i=0; i<NBANKS; i++) |
m_bank_status[i] &= 0x03; |
} else { |
// Precharge/close single bank |
assert(0 == (bs & (~3))); // Assert w/in bounds |
m_bank_status[bs] &= 0x03; // Close the bank |
|
printf("Precharging bank %d\n", bs); |
} |
} else if ((!cs_n)&&(!ras_n)&&(cas_n)&&(we_n)) { |
printf("Activating bank %d\n", bs); |
// Activate a bank! |
if (0 != (bs & (~3))) { |
m_fail = 2; |
fprintf(stderr, "ERR: Activating a bank w/ more than 2 bits\n"); |
// assert(0 == (bs & (~3))); // Assert w/in bounds |
} else if (m_bank_status[bs] != 0) { |
fprintf(stderr, "ERR: Status of bank [bs=%d] = %d != 0\n", |
bs, m_bank_status[bs]); |
m_fail = 4; |
// assert(m_bank_status[bs]==0); // Assert bank was closed |
} |
m_bank_status[bs] |= 4; |
m_bank_open_time[bs] = MAX_BANKOPEN_TIME; |
m_bank_row[bs] = addr; |
} else if ((!cs_n)&&(ras_n)&&(!cas_n)) { |
printf("R/W Op\n"); |
if (!we_n) { |
// Initiate a write |
assert(0 == (bs & (~3))); // Assert w/in bounds |
assert(m_bank_status[bs]&1); // Assert bank is open |
|
m_wr_addr = m_bank_row[bs]; |
m_wr_addr <<= 2; |
m_wr_addr |= bs; |
m_wr_addr <<= 9; |
m_wr_addr |= (addr & 0x01ff); |
|
assert(driv); |
printf("SDRAM[%08x] <= %04x\n", m_wr_addr, data & 0x0ffff); |
m_mem[m_wr_addr++] = data; |
m_clocks_till_idle = 2; |
m_next_wr = true; |
|
if (addr & 0x0400) { // Auto precharge |
m_bank_status[bs] &= 3; |
m_bank_open_time[bs] = MAX_BANKOPEN_TIME; |
} |
} else { // Initiate a read |
assert(0 == (bs & (~3))); // Assert w/in bounds |
assert(m_bank_status[bs]&1); // Assert bank is open |
|
unsigned rd_addr; |
|
rd_addr = m_bank_row[bs] & 0x01fff; |
rd_addr <<= 2; |
rd_addr |= bs; |
rd_addr <<= 9; |
rd_addr |= (addr & 0x01ff); |
|
assert(!driv); |
printf("SDRAM.Q %04x <= SDRAM[%08x]\n", |
m_mem[rd_addr] & 0x0ffff, rd_addr); |
m_qdata[(m_qloc+1)&m_qmask] = m_mem[rd_addr++]; |
printf("SDRAM.Q %04x <= SDRAM[%08x]\n", |
m_mem[rd_addr] & 0x0ffff, rd_addr); |
m_qdata[(m_qloc+2)&m_qmask] = m_mem[rd_addr++]; |
m_clocks_till_idle = 2; |
|
if (addr & 0x0400) { // Auto precharge |
m_bank_status[bs] &= 3; |
m_bank_open_time[bs] = MAX_BANKOPEN_TIME; |
} |
} |
} else if (cs_n) { |
// Chips not asserted, DESELECT CMD equivalent of a NOOP |
} else if ((ras_n)&&(cas_n)&&(we_n)) { |
// NOOP command |
} else { |
fprintf(stderr, "Unrecognized memory command!\n"); |
fprintf(stderr, "\tCS_n = %d\n", cs_n); |
fprintf(stderr, "\tRAS_n = %d\n", ras_n); |
fprintf(stderr, "\tCAS_n = %d\n", cas_n); |
fprintf(stderr, "\tWE_n = %d\n", we_n); |
assert(0 && "Unrecognizned command"); |
} |
} |
|
return result & 0x0ffff; |
} |
|
|
/trunk/bench/cpp/pipecmdr.cpp
0,0 → 1,107
// |
// |
// Filename: pipecmdr.cpp |
// |
// Project: FPGA testbench utilities. |
// |
// Purpose: This program attaches to a Verilated Verilog IP core. |
// It will not work apart from such a core. Once attached, |
// it connects the simulated core to a controller via a |
// pipe interface designed to act like a UART. Indeed, it |
// is hoped that the final interface would be via UART. Until |
// that point, however, this is just a simple test facility |
// designed to verify that the IP core works prior to such |
// actual hardware implementation. |
// |
// Creator: Dan Gisselquist |
// Gisselquist Tecnology, LLC |
// |
// Copyright: 2015 |
// |
// |
|
class PIPECMDR { |
public: |
int m_skt, m_con; |
char m_txbuf[256], m_rxbuf[256]; |
int m_ilen, m_rxpos, m_txpos; |
|
setup_listener(port); |
UARTIPCMDR(const int port) { |
setup_listener(port); |
} |
|
void tick(void) { |
if (m_fd <= 0) { |
// Can we accept a connection? |
struct pollfd pb; |
|
pb.fd = m_skt; |
pb.events = POLLIN; |
poll(&pb, 1, 0); |
|
if (pb.revents & POLLIN) { |
m_fd = accept(m_skt, 0, 0); |
} |
} |
|
m_core->i_uart_rd = 0; |
if (m_ilen > 0) { |
// Is there a byte in our buffer somewhere? |
m_core->i_uart_rd = 1; |
m_core->i_uart_data = m_rxbuf[m_pos++]; |
m_ilen--; |
} else if (m_fd > 0) { |
// Is there a byte to be read here? |
struct pollfd pb; |
pb.fd = m_fd; |
pb.events = POLLIN; |
poll(&pb, 1, 0); |
if (pb.revents & POLLIN) { |
char buf[2]; |
if ((m_ilen =recv(m_fd, m_rxbuf, sizeof(m_rxbuf), MSG_DONTWAIT)) > 0) { |
m_core->i_uart_rd = 1; |
m_core->i_uart_data = m_rxbuf[0]; |
m_pos = 1; m_ilen--; |
} else { // the connection closed on us |
close(m_fd); |
m_fd = -1; |
} |
} |
} |
|
tick(); |
|
if ((m_core->o_uart_tx)&&(m_fd > 0)) { |
m_txbuf[m_txpos++] = m_core->o_uart_data; |
if ((m_core->o_uart_data == '\n')||(m_txpos >= sizeof(m_txbuf))) { |
send(m_fd, m_txbuf, m_txpos, 0); |
m_txpos = 0; |
} |
} |
} |
}; |
|
void PIPECMDR::setup_listener(void) { |
printf("Listening on port %d\n", PORT); |
|
m_skt = socket(AF_INET, SOCK_STREAM, 0); |
|
{ |
int optval = 1, er; |
er = setsockopt(m_skt, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); |
if (er != 0) { |
perror("SockOpt Err: "); |
exit(-2); |
} |
} |
|
memset(&my_addr, 0, sizeof(struct sockaddr_un)); // clear structure |
my-addr.sin_family = AF_INET; |
my_addr.sin_addr.s_addr = htonl(INADDR_ANY); |
my_addr.sin_port = htons(PORT); |
|
bind(m_skt, (SA *)&my_addr, sizeof(my_addr)); |
listen(m_skt, 1); |
} |
|
/trunk/bench/cpp/qspiflashsim.cpp
0,0 → 1,470
/////////////////////////////////////////////////////////////////////////// |
// |
// |
// Filename: spiflashsim.cpp |
// |
// Project: Wishbone Controlled Quad SPI Flash Controller |
// |
// Purpose: This library simulates the operation of a Quad-SPI commanded |
// flash, such as the S25FL032P used on the Basys-3 development |
// board by Digilent. As such, it is defined by 32 Mbits of |
// memory (4 Mbyte). |
// |
// This simulator is useful for testing in a Verilator/C++ |
// environment, where this simulator can be used in place of |
// the actual hardware. |
// |
// Creator: Dan Gisselquist |
// Gisselquist Technology, LLC |
// |
/////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory, run make with no |
// target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
/////////////////////////////////////////////////////////////////////////// |
#include <stdio.h> |
#include <string.h> |
#include <assert.h> |
#include <stdlib.h> |
|
#include "qspiflashsim.h" |
|
#define MEMBYTES (1<<22) |
|
static const unsigned DEVID = 0x0115, |
DEVESD = 0x014, |
MICROSECONDS = 100, |
MILLISECONDS = MICROSECONDS * 1000, |
SECONDS = MILLISECONDS * 1000, |
tW = 50 * MICROSECONDS, // write config cycle time |
tBE = 32 * SECONDS, |
tDP = 10 * SECONDS, |
tRES = 30 * SECONDS, |
// Shall we artificially speed up this process? |
tPP = 12 * MICROSECONDS, |
tSE = 15 * MILLISECONDS; |
// or keep it at the original speed |
// tPP = 1200 * MICROSECONDS, |
// tSE = 1500 * MILLISECONDS; |
|
QSPIFLASHSIM::QSPIFLASHSIM(void) { |
m_mem = new char[MEMBYTES]; |
m_pmem = new char[256]; |
m_state = QSPIF_IDLE; |
m_last_sck = 1; |
m_write_count = 0; |
m_ireg = m_oreg = 0; |
m_sreg = 0x01c; |
m_creg = 0x001; // Iinitial creg on delivery |
m_quad_mode = false; |
m_mode_byte = 0; |
|
memset(m_mem, 0x0ff, MEMBYTES); |
} |
|
void QSPIFLASHSIM::load(const char *fname) { |
FILE *fp; |
int nr = 0; |
|
if (NULL != (fp = fopen(fname, "r"))) { |
nr = fread(m_mem, sizeof(char), MEMBYTES, fp); |
fclose(fp); |
} else { |
fprintf(stderr, "SPI-FLASH: Could not open %s\n", fname); |
perror("O/S Err:"); |
} |
|
for(int i=nr; i<MEMBYTES; i++) |
m_mem[i] = 0x0ff; |
} |
|
#define QOREG(A) m_oreg = ((m_oreg & (~0x0ff))|(A&0x0ff)) |
|
int QSPIFLASHSIM::operator()(const int csn, const int sck, const int dat) { |
// Keep track of a timer to determine when page program and erase |
// cycles complete. |
|
if (m_write_count > 0) { |
if (0 == (--m_write_count)) {// When done with erase/page pgm, |
m_sreg &= 0x0fc; // Clear the write in progress bit |
if (m_debug) printf("Write complete, clearing WIP (inside SIM)\n"); |
} |
} |
|
if (csn) { |
m_last_sck = 1; |
m_ireg = 0; m_oreg = 0; |
m_count= 0; |
|
if ((QSPIF_PP == m_state)||(QSPIF_QPP == m_state)) { |
// Start a page program |
if (m_debug) printf("QSPI: Page Program write cycle begins\n"); |
if (m_debug) printf("CK = %d & 7 = %d\n", m_count, m_count & 0x07); |
if (m_debug) printf("QSPI: pmem = %08lx\n", (unsigned long)m_pmem); |
m_write_count = tPP; |
m_state = QSPIF_IDLE; |
m_sreg &= (~QSPIF_WEL_FLAG); |
m_sreg |= (QSPIF_WIP_FLAG); |
for(int i=0; i<256; i++) { |
/* |
if (m_debug) printf("%02x: m_mem[%02x] = %02x &= %02x = %02x\n", |
i, (m_addr&(~0x0ff))+i, |
m_mem[(m_addr&(~0x0ff))+i]&0x0ff, m_pmem[i]&0x0ff, |
m_mem[(m_addr&(~0x0ff))+i]& m_pmem[i]&0x0ff); |
*/ |
m_mem[(m_addr&(~0x0ff))+i] &= m_pmem[i]; |
} |
m_quad_mode = false; |
} else if (m_state == QSPIF_SECTOR_ERASE) { |
if (m_debug) printf("Actually Erasing sector, from %08x\n", m_addr); |
m_write_count = tSE; |
m_state = QSPIF_IDLE; |
m_sreg &= (~QSPIF_WEL_FLAG); |
m_sreg |= (QSPIF_WIP_FLAG); |
m_addr &= (-1<<16); |
for(int i=0; i<(1<<16); i++) |
m_mem[m_addr + i] = 0x0ff; |
if (m_debug) printf("Now waiting %d ticks delay\n", m_write_count); |
} else if (QSPIF_WRSR == m_state) { |
if (m_debug) printf("Actually writing status register\n"); |
m_write_count = tW; |
m_state = QSPIF_IDLE; |
m_sreg &= (~QSPIF_WEL_FLAG); |
m_sreg |= (QSPIF_WIP_FLAG); |
} else if (QSPIF_CLSR == m_state) { |
if (m_debug) printf("Actually clearing the status register bits\n"); |
m_state = QSPIF_IDLE; |
m_sreg &= 0x09f; |
} else if (m_state == QSPIF_BULK_ERASE) { |
m_write_count = tBE; |
m_state = QSPIF_IDLE; |
m_sreg &= (~QSPIF_WEL_FLAG); |
m_sreg |= (QSPIF_WIP_FLAG); |
for(int i=0; i<MEMBYTES; i++) |
m_mem[i] = 0x0ff; |
} else if (m_state == QSPIF_DEEP_POWER_DOWN) { |
m_write_count = tDP; |
m_state = QSPIF_IDLE; |
} else if (m_state == QSPIF_RELEASE) { |
m_write_count = tRES; |
m_state = QSPIF_IDLE; |
} else if (m_state == QSPIF_QUAD_READ_CMD) { |
if ((m_mode_byte & 0x0f0)!=0x0a0) |
m_quad_mode = false; |
else |
m_state = QSPIF_QUAD_READ_IDLE; |
} else if (m_state == QSPIF_QUAD_READ) { |
if ((m_mode_byte & 0x0f0)!=0x0a0) |
m_quad_mode = false; |
else |
m_state = QSPIF_QUAD_READ_IDLE; |
} else if (m_state == QSPIF_QUAD_READ_IDLE) { |
} |
|
m_oreg = 0x0fe; |
return dat; |
} else if ((!m_last_sck)||(sck == m_last_sck)) { |
// Only change on the falling clock edge |
// printf("SFLASH-SKIP, CLK=%d -> %d\n", m_last_sck, sck); |
m_last_sck = sck; |
if (m_quad_mode) |
return (m_oreg>>8)&0x0f; |
else |
// return ((m_oreg & 0x0100)?2:0) | (dat & 0x0d); |
return (m_oreg & 0x0100)?2:0; |
} |
|
// We'll only get here if ... |
// last_sck = 1, and sck = 0, thus transitioning on the |
// negative edge as with everything else in this interface |
if (m_quad_mode) { |
m_ireg = (m_ireg << 4) | (dat & 0x0f); |
m_count+=4; |
m_oreg <<= 4; |
} else { |
m_ireg = (m_ireg << 1) | (dat & 1); |
m_count++; |
m_oreg <<= 1; |
} |
|
|
// printf("PROCESS, COUNT = %d, IREG = %02x\n", m_count, m_ireg); |
if (m_state == QSPIF_QUAD_READ_IDLE) { |
assert(m_quad_mode); |
if (m_count == 24) { |
if (m_debug) printf("QSPI: Entering from Quad-Read Idle to Quad-Read\n"); |
if (m_debug) printf("QSPI: QI/O Idle Addr = %02x\n", m_ireg&0x0ffffff); |
m_addr = (m_ireg) & 0x0ffffff; |
assert((m_addr & 0xfc00000)==0); |
m_state = QSPIF_QUAD_READ; |
} m_oreg = 0; |
} else if (m_count == 8) { |
QOREG(0x0a5); |
// printf("SFLASH-CMD = %02x\n", m_ireg & 0x0ff); |
// Figure out what command we've been given |
if (m_debug) printf("SPI FLASH CMD %02x\n", m_ireg&0x0ff); |
switch(m_ireg & 0x0ff) { |
case 0x01: // Write status register |
if (2 !=(m_sreg & 0x203)) { |
if (m_debug) printf("QSPI: WEL not set, cannot write status reg\n"); |
m_state = QSPIF_INVALID; |
} else |
m_state = QSPIF_WRSR; |
break; |
case 0x02: // Page program |
if (2 != (m_sreg & 0x203)) { |
if (m_debug) printf("QSPI: Cannot program at this time, SREG = %x\n", m_sreg); |
m_state = QSPIF_INVALID; |
} else { |
m_state = QSPIF_PP; |
if (m_debug) printf("PAGE-PROGRAM COMMAND ACCEPTED\n"); |
} |
break; |
case 0x03: // Read data bytes |
// Our clock won't support this command, so go |
// to an invalid state |
if (m_debug) printf("QSPI INVALID: This sim does not support slow reading\n"); |
m_state = QSPIF_INVALID; |
break; |
case 0x04: // Write disable |
m_state = QSPIF_IDLE; |
m_sreg &= (~QSPIF_WEL_FLAG); |
break; |
case 0x05: // Read status register |
m_state = QSPIF_RDSR; |
if (m_debug) printf("QSPI: READING STATUS REGISTER: %02x\n", m_sreg); |
QOREG(m_sreg); |
break; |
case 0x06: // Write enable |
m_state = QSPIF_IDLE; |
m_sreg |= QSPIF_WEL_FLAG; |
if (m_debug) printf("QSPI: WRITE-ENABLE COMMAND ACCEPTED\n"); |
break; |
case 0x0b: // Here's the read that we support |
if (m_debug) printf("QSPI: FAST-READ (single-bit)\n"); |
m_state = QSPIF_FAST_READ; |
break; |
case 0x30: |
if (m_debug) printf("QSPI: CLEAR STATUS REGISTER COMMAND\n"); |
m_state = QSPIF_CLSR; |
break; |
case 0x32: // QUAD Page program, 4 bits at a time |
if (2 != (m_sreg & 0x203)) { |
if (m_debug) printf("QSPI: Cannot program at this time, SREG = %x\n", m_sreg); |
m_state = QSPIF_INVALID; |
} else { |
m_state = QSPIF_QPP; |
if (m_debug) printf("QSPI: QUAD-PAGE-PROGRAM COMMAND ACCEPTED\n"); |
if (m_debug) printf("QSPI: pmem = %08lx\n", (unsigned long)m_pmem); |
} |
break; |
case 0x35: // Read configuration register |
m_state = QSPIF_RDCR; |
if (m_debug) printf("QSPI: READING CONFIGURATION REGISTER: %02x\n", m_creg); |
QOREG(m_creg); |
break; |
case 0x9f: // Read ID |
m_state = QSPIF_RDID; |
if (m_debug) printf("QSPI: READING ID, %02x\n", (DEVID>>24)&0x0ff); |
QOREG(0xfe); |
break; |
case 0xab: // Release from DEEP POWER DOWN |
if (m_sreg & QSPIF_DEEP_POWER_DOWN_FLAG) { |
if (m_debug) printf("QSPI: Release from deep power down\n"); |
m_sreg &= (~QSPIF_DEEP_POWER_DOWN_FLAG); |
m_write_count = tRES; |
} m_state = QSPIF_RELEASE; |
break; |
case 0xb9: // DEEP POWER DOWN |
if (0 != (m_sreg & 0x01)) { |
if (m_debug) printf("QSPI: Cannot enter DEEP POWER DOWN, in middle of write/erase\n"); |
m_state = QSPIF_INVALID; |
} else { |
m_sreg |= QSPIF_DEEP_POWER_DOWN_FLAG; |
m_state = QSPIF_IDLE; |
} |
break; |
case 0xc7: // Bulk Erase |
if (2 != (m_sreg & 0x203)) { |
if (m_debug) printf("QSPI: WEL not set, cannot erase device\n"); |
m_state = QSPIF_INVALID; |
} else |
m_state = QSPIF_BULK_ERASE; |
break; |
case 0xd8: // Sector Erase |
if (2 != (m_sreg & 0x203)) { |
if (m_debug) printf("QSPI: WEL not set, cannot erase sector\n"); |
m_state = QSPIF_INVALID; |
} else { |
m_state = QSPIF_SECTOR_ERASE; |
if (m_debug) printf("QSPI: SECTOR_ERASE COMMAND\n"); |
} |
break; |
case 0x0eb: // Here's the (other) read that we support |
// printf("QSPI: QUAD-I/O-READ\n"); |
m_state = QSPIF_QUAD_READ_CMD; |
m_quad_mode = true; |
break; |
default: |
printf("QSPI: UNRECOGNIZED SPI FLASH CMD: %02x\n", m_ireg&0x0ff); |
m_state = QSPIF_INVALID; |
assert(0 && "Unrecognized command\n"); |
break; |
} |
} else if ((0 == (m_count&0x07))&&(m_count != 0)) { |
QOREG(0); |
switch(m_state) { |
case QSPIF_IDLE: |
printf("TOO MANY CLOCKS, SPIF in IDLE\n"); |
break; |
case QSPIF_WRSR: |
if (m_count == 16) { |
m_sreg = (m_sreg & 0x061) | (m_ireg & 0x09c); |
if (m_debug) printf("Request to set sreg to 0x%02x\n", |
m_ireg&0x0ff); |
} else if (m_count == 24) { |
m_creg = (m_creg & 0x0fd) | (m_ireg & 0x02); |
if (m_debug) printf("Request to set creg to 0x%02x\n", |
m_ireg&0x0ff); |
} else { |
printf("TOO MANY CLOCKS FOR WRR!!!\n"); |
exit(-2); |
m_state = QSPIF_IDLE; |
} |
break; |
case QSPIF_CLSR: |
assert(0 && "Too many clocks for CLSR command!!\n"); |
break; |
case QSPIF_RDID: |
if (m_count == 32) { |
m_addr = m_ireg & 0x0ffffff; |
if (m_debug) printf("READID, ADDR = %08x\n", m_addr); |
QOREG((DEVID>>8)); |
if (m_debug) printf("QSPI: READING ID, %02x\n", (DEVID>>8)&0x0ff); |
} else if (m_count > 32) { |
if (((m_count-32)>>3)&1) |
QOREG((DEVID)); |
else |
QOREG((DEVID>>8)); |
if (m_debug) printf("QSPI: READING ID, %02x -- DONE\n", 0x00); |
} |
// m_oreg = (DEVID >> (2-(m_count>>3)-1)) & 0x0ff; |
break; |
case QSPIF_RDSR: |
// printf("Read SREG = %02x, wait = %08x\n", m_sreg, |
// m_write_count); |
QOREG(m_sreg); |
break; |
case QSPIF_RDCR: |
if (m_debug) printf("Read CREG = %02x\n", m_creg); |
QOREG(m_creg); |
break; |
case QSPIF_FAST_READ: |
if (m_count == 32) { |
m_addr = m_ireg & 0x0ffffff; |
if (m_debug) printf("FAST READ, ADDR = %08x\n", m_addr); |
QOREG(0x0c3); |
assert((m_addr & 0xfc00000)==0); |
} else if ((m_count >= 40)&&(0 == (m_sreg&0x01))) { |
if (m_count == 40) |
printf("DUMMY BYTE COMPLETE ...\n"); |
QOREG(m_mem[m_addr++]); |
// if (m_debug) printf("SPIF[%08x] = %02x\n", m_addr-1, m_oreg); |
} else m_oreg = 0; |
break; |
case QSPIF_QUAD_READ_CMD: |
// The command to go into quad read mode took 8 bits |
// that changes the timings, else we'd use quad_Read |
// below |
if (m_count == 32) { |
m_addr = m_ireg & 0x0ffffff; |
// printf("FAST READ, ADDR = %08x\n", m_addr); |
// printf("QSPI: QUAD READ, ADDR = %06x\n", m_addr); |
assert((m_addr & 0xfc00000)==0); |
} else if (m_count == 32+24) { |
m_mode_byte = (m_ireg>>16) & 0x0ff; |
// printf("QSPI: MODE BYTE = %02x\n", m_mode_byte); |
} else if ((m_count > 32+24)&&(0 == (m_sreg&0x01))) { |
QOREG(m_mem[m_addr++]); |
// printf("QSPIF[%08x]/QR = %02x\n", |
// m_addr-1, m_oreg); |
} else m_oreg = 0; |
break; |
case QSPIF_QUAD_READ: |
if (m_count == 32) { |
m_mode_byte = (m_ireg & 0x0ff); |
// printf("QSPI/QR: MODE BYTE = %02x\n", m_mode_byte); |
} else if ((m_count >= 32+16)&&(0 == (m_sreg&0x01))) { |
QOREG(m_mem[m_addr++]); |
// printf("QSPIF[%08x]/QR = %02x\n", m_addr-1, m_oreg & 0x0ff); |
} else m_oreg = 0; |
break; |
case QSPIF_PP: |
if (m_count == 32) { |
m_addr = m_ireg & 0x0ffffff; |
if (m_debug) printf("QSPI: PAGE-PROGRAM ADDR = %06x\n", m_addr); |
assert((m_addr & 0xfc00000)==0); |
// m_page = m_addr >> 8; |
for(int i=0; i<256; i++) |
m_pmem[i] = 0x0ff; |
} else if (m_count >= 40) { |
m_pmem[m_addr & 0x0ff] = m_ireg & 0x0ff; |
// printf("QSPI: PMEM[%02x] = 0x%02x -> %02x\n", m_addr & 0x0ff, m_ireg & 0x0ff, (m_pmem[(m_addr & 0x0ff)]&0x0ff)); |
m_addr = (m_addr & (~0x0ff)) | ((m_addr+1)&0x0ff); |
} break; |
case QSPIF_QPP: |
if (m_count == 32) { |
m_addr = m_ireg & 0x0ffffff; |
m_quad_mode = true; |
if (m_debug) printf("QSPI/QR: PAGE-PROGRAM ADDR = %06x\n", m_addr); |
assert((m_addr & 0xfc00000)==0); |
// m_page = m_addr >> 8; |
for(int i=0; i<256; i++) |
m_pmem[i] = 0x0ff; |
} else if (m_count >= 40) { |
m_pmem[m_addr & 0x0ff] = m_ireg & 0x0ff; |
// printf("QSPI/QR: PMEM[%02x] = 0x%02x -> %02x\n", m_addr & 0x0ff, m_ireg & 0x0ff, (m_pmem[(m_addr & 0x0ff)]&0x0ff)); |
m_addr = (m_addr & (~0x0ff)) | ((m_addr+1)&0x0ff); |
} break; |
case QSPIF_SECTOR_ERASE: |
if (m_count == 32) { |
m_addr = m_ireg & 0x0ffc000; |
if (m_debug) printf("SECTOR_ERASE ADDRESS = %08x\n", m_addr); |
assert((m_addr & 0xfc00000)==0); |
} break; |
case QSPIF_RELEASE: |
if (m_count >= 32) { |
QOREG(DEVESD); |
} break; |
default: |
break; |
} |
} // else printf("SFLASH->count = %d\n", m_count); |
|
m_last_sck = sck; |
if (m_quad_mode) |
return (m_oreg>>8)&0x0f; |
else |
// return ((m_oreg & 0x0100)?2:0) | (dat & 0x0d); |
return (m_oreg & 0x0100)?2:0; |
} |
|
/trunk/bench/cpp/sdramsim.h
0,0 → 1,57
#ifndef SDRAMSIM_H |
|
#define NBANKS 4 |
#define POWERED_UP_STATE 6 |
#define CLK_RATE_HZ 100000000 // = 100 MHz = 100 * 10^6 |
#define PWRUP_WAIT_CKS ((int)(.000200 * CLK_RATE_HZ)) |
#define MAX_BANKOPEN_TIME ((int)(.000100 * CLK_RATE_HZ)) |
#define MAX_REFRESH_TIME ((int)(.064 * CLK_RATE_HZ)) |
|
class SDRAMSIM { |
int m_pwrup; |
short *m_mem; |
short m_last_value, m_qmem[4]; |
int m_bank_status[NBANKS]; |
int m_bank_row[NBANKS]; |
int m_bank_open_time[NBANKS]; |
unsigned *m_refresh_time; |
int m_refresh_loc, m_nrefresh; |
int m_qloc, m_qdata[8], m_qmask, m_wr_addr; |
int m_clocks_till_idle; |
bool m_next_wr; |
unsigned m_fail; |
public: |
SDRAMSIM(void) { |
m_mem = new short[(1<<24)]; // 32 MB, or 16 Mshorts |
|
m_refresh_time = new unsigned[(1<<13)]; |
for(int i=0; i<m_nrefresh; i++) |
m_refresh_time[i] = 0; |
m_refresh_loc = 0; |
|
m_pwrup = 0; |
m_clocks_till_idle = 0; |
|
m_last_value = 0; |
m_clocks_till_idle = PWRUP_WAIT_CKS; |
m_wr_addr = 0; |
|
m_qloc = 0; |
m_qmask = 7; |
|
m_next_wr = true; |
m_fail = 0; |
} |
|
~SDRAMSIM(void) { |
delete m_mem; |
} |
|
short operator()(int clk, int cke, |
int cs_n, int ras_n, int cas_n, int we_n, int bs, |
unsigned addr, |
int driv, short data); |
int pwrup(void) const { return m_pwrup; } |
}; |
|
#endif |
/trunk/bench/cpp/testb.h
0,0 → 1,70
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: testb.h |
// |
// Project: Zip CPU -- a small, lightweight, RISC CPU core |
// |
// Purpose: A wrapper for a common interface to a clocked FPGA core |
// begin exercised in Verilator. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Tecnology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// |
// This program is free software (firmware): you can redistribute it and/or |
// modify it under the terms of the GNU General Public License as published |
// by the Free Software Foundation, either version 3 of the License, or (at |
// your option) any later version. |
// |
// This program is distributed in the hope that it will be useful, but WITHOUT |
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with this program. (It's in the $(ROOT)/doc directory, run make with no |
// target there if the PDF file isn't present.) If not, see |
// <http://www.gnu.org/licenses/> for a copy. |
// |
// License: GPL, v3, as defined and found on www.gnu.org, |
// http://www.gnu.org/licenses/gpl.html |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
#ifndef TESTB_H |
#define TESTB_H |
|
template <class VA> class TESTB { |
public: |
VA *m_core; |
unsigned long m_tickcount; |
|
TESTB(void) { m_core = new VA; } |
~TESTB(void) { delete m_core; m_core = NULL; } |
|
virtual void eval(void) { |
m_core->eval(); |
} |
|
virtual void tick(void) { |
m_core->i_clk = 1; |
eval(); |
m_core->i_clk = 0; |
eval(); |
|
m_tickcount++; |
} |
|
virtual void reset(void) { |
m_core->i_rst = 1; |
tick(); |
m_core->i_rst = 0; |
m_tickcount = 0l; |
// printf("RESET\n"); |
} |
}; |
|
#endif |
/trunk/bench/cpp/usbi.h
0,0 → 1,70
link ../../sw/usbi.h |
trunk/bench/cpp/usbi.h
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/bench/cpp/pipecmdr.h
===================================================================
--- trunk/bench/cpp/pipecmdr.h (nonexistent)
+++ trunk/bench/cpp/pipecmdr.h (revision 4)
@@ -0,0 +1,217 @@
+//
+//
+// Filename: pipecmdr.h
+//
+// Project: FPGA testbench utilities.
+//
+// Purpose: This program attaches to a Verilated Verilog IP core.
+// It will not work apart from such a core. Once attached,
+// it connects the simulated core to a controller via a
+// pipe interface designed to act like a UART. Indeed, it
+// is hoped that the final interface would be via UART. Until
+// that point, however, this is just a simple test facility
+// designed to verify that the IP core works prior to such
+// actual hardware implementation.
+//
+// Creator: Dan Gisselquist
+// Gisselquist Tecnology, LLC
+//
+// Copyright: 2015
+//
+//
+#ifndef PIPECMDR_H
+#define PIPECMDR_H
+
+#include
+#include
+#include
+#include
+#include
+
+#include "testb.h"
+
+#define PIPEBUFLEN 256
+
+// At 115200 Baud, 8 bits of data, no parity and one stop bit, there will
+// bit ten bits per character and therefore 8681 clocks per transfer
+// 8681 ~= 100 MHz / 115200 (bauds / second) * 10 bauds / character
+//
+// #define UARTLEN 8681 // Minimum ticks per character, 115200 Baud
+//
+// At 4MBaud, each bit takes 25 clocks. 10 bits would thus take 250 clocks
+//
+#define UARTLEN 250 // Minimum ticks per character, 4M Baud
+// #define UARTLEN 8 // Minimum ticks per character
+
+template class PIPECMDR : public TESTB {
+ void setup_listener(const int port) {
+ struct sockaddr_in my_addr;
+
+ printf("Listening on port %d\n", port);
+
+ m_skt = socket(AF_INET, SOCK_STREAM, 0);
+ if (m_skt < 0) {
+ perror("Could not allocate socket: ");
+ exit(-1);
+ }
+
+ // Set the reuse address option
+ {
+ int optv = 1, er;
+ er = setsockopt(m_skt, SOL_SOCKET, SO_REUSEADDR, &optv, sizeof(optv));
+ if (er != 0) {
+ perror("SockOpt Err:");
+ exit(-1);
+ }
+ }
+
+ memset(&my_addr, 0, sizeof(struct sockaddr_in)); // clear structure
+ my_addr.sin_family = AF_INET;
+ my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ my_addr.sin_port = htons(port);
+
+ if (bind(m_skt, (struct sockaddr *)&my_addr, sizeof(my_addr))!=0) {
+ perror("BIND FAILED:");
+ exit(-1);
+ }
+
+ if (listen(m_skt, 1) != 0) {
+ perror("Listen failed:");
+ exit(-1);
+ }
+ }
+
+public:
+ int m_skt, m_con;
+ char m_txbuf[PIPEBUFLEN], m_rxbuf[PIPEBUFLEN];
+ int m_ilen, m_rxpos, m_txpos, m_uart_wait;
+ bool m_started_flag;
+
+ PIPECMDR(const int port) : TESTB() {
+ m_con = m_skt = -1;
+ setup_listener(port);
+ m_rxpos = m_txpos = m_ilen = 0;
+ m_started_flag = false;
+ m_uart_wait = 0;
+ }
+
+ virtual void kill(void) {
+ // Close any active connection
+ if (m_con >= 0) close(m_con);
+ if (m_skt >= 0) close(m_skt);
+ }
+
+ virtual void tick(void) {
+ if (m_con < 0) {
+ // Can we accept a connection?
+ struct pollfd pb;
+
+ pb.fd = m_skt;
+ pb.events = POLLIN;
+ poll(&pb, 1, 0);
+
+ if (pb.revents & POLLIN) {
+ m_con = accept(m_skt, 0, 0);
+
+ if (m_con < 0)
+ perror("Accept failed:");
+ }
+ }
+
+ TESTB::m_core->i_rx_stb = 0;
+
+ if (m_uart_wait == 0) {
+ if (m_ilen > 0) {
+ // Is there a byte in our buffer somewhere?
+ TESTB::m_core->i_rx_stb = 1;
+ TESTB::m_core->i_rx_data = m_rxbuf[m_rxpos++];
+ m_ilen--;
+ } else if (m_con > 0) {
+ // Is there a byte to be read here?
+ struct pollfd pb;
+ pb.fd = m_con;
+ pb.events = POLLIN;
+ if (poll(&pb, 1, 0) < 0)
+ perror("Polling error:");
+ if (pb.revents & POLLIN) {
+ if ((m_ilen =recv(m_con, m_rxbuf, sizeof(m_rxbuf), MSG_DONTWAIT)) > 0) {
+ m_rxbuf[m_ilen] = '\0';
+ if (m_rxbuf[m_ilen-1] == '\n') {
+ m_rxbuf[m_ilen-1] = '\0';
+ printf("< \'%s\'\n", m_rxbuf);
+ m_rxbuf[m_ilen-1] = '\n';
+ } else printf("< \'%s\'\n", m_rxbuf);
+ TESTB::m_core->i_rx_stb = 1;
+ TESTB::m_core->i_rx_data = m_rxbuf[0];
+ m_rxpos = 1; m_ilen--;
+ m_started_flag = true;
+ } else if (m_ilen < 0) {
+ // An error occurred, close the connection
+ perror("Read error: ");
+ fprintf(stderr, "Closing connection\n");
+ close(m_con);
+ m_con = -1;
+ } else { // the connection closed on us
+ close(m_con);
+ m_con = -1;
+ }
+ }
+ } m_uart_wait = (TESTB::m_core->i_rx_stb)?UARTLEN:0;
+ } else {
+ // Still working on transmitting a character
+ m_uart_wait = m_uart_wait - 1;
+ }
+
+ /*
+ if (TESTB::m_core->i_rx_stb) {
+ putchar(TESTB::m_core->i_rx_data);
+ fflush(stdout);
+ }
+ */
+ TESTB::tick();
+
+ if ((TESTB::m_core->o_tx_stb)&&(m_con > 0)) {
+ m_txbuf[m_txpos++] = TESTB::m_core->o_tx_data;
+ if ((TESTB::m_core->o_tx_data == '\n')||(m_txpos >= sizeof(m_txbuf))) {
+ int snt = 0;
+ snt = send(m_con, m_txbuf, m_txpos, 0);
+
+ m_txbuf[m_txpos] = '\0';
+ printf("> %s", m_txbuf);
+ if (snt < m_txpos) {
+ fprintf(stderr, "Only sent %d bytes!\n",
+ snt);
+ }
+ m_txpos = 0;
+ }
+ }
+
+ /*
+ if((TESTB::m_core->o_wb_cyc)||(TESTB::m_core->o_wb_stb)){
+ printf("BUS: %d,%d,%d %8x %8x\n",
+ TESTB::m_core->o_wb_cyc,
+ TESTB::m_core->o_wb_stb,
+ TESTB::m_core->o_wb_we,
+ TESTB::m_core->o_wb_addr,
+ TESTB::m_core->o_wb_data);
+ } else if (m_started_flag) {
+ printf("%02x,%c,%d,%d,%02x -> %d,%d,%d, %2x,%2x,%2x\n",
+ TESTB::m_core->i_rx_data,
+ (TESTB::m_core->i_rx_stb)?(TESTB::m_core->i_rx_data):' ',
+ TESTB::m_core->v__DOT__decodewb__DOT__r_valid,
+ TESTB::m_core->v__DOT__decodewb__DOT__rx_eol,
+ TESTB::m_core->v__DOT__decodewb__DOT__rx_six_bits,
+ //
+ TESTB::m_core->v__DOT__decodewb__DOT__o_rq_strobe,
+ TESTB::m_core->v__DOT__decodewb__DOT__o_rq_hold,
+ TESTB::m_core->v__DOT__decodewb__DOT__o_rq_we,
+ //
+ TESTB::m_core->v__DOT__decodewb__DOT__state,
+ TESTB::m_core->v__DOT__decodewb__DOT__nreg,
+ TESTB::m_core->v__DOT__decodewb__DOT__szreg);
+ }
+ */
+ }
+};
+
+#endif
Index: trunk/bench/cpp/qspiflashsim.h
===================================================================
--- trunk/bench/cpp/qspiflashsim.h (nonexistent)
+++ trunk/bench/cpp/qspiflashsim.h (revision 4)
@@ -0,0 +1,81 @@
+///////////////////////////////////////////////////////////////////////////
+//
+// Filename: spiflashsim.h
+//
+// Project: Wishbone Controlled Quad SPI Flash Controller
+//
+// Purpose: This library simulates the operation of a Quad-SPI commanded
+// flash, such as the S25FL032P used on the Basys-3 development
+// board by Digilent. As such, it is defined by 32 Mbits of
+// memory (4 Mbyte).
+//
+// Creator: Dan Gisselquist
+// Gisselquist Technology, LLC
+//
+///////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2015, Gisselquist Technology, LLC
+//
+// This program is free software (firmware): you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as published
+// by the Free Software Foundation, either version 3 of the License, or (at
+// your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program. (It's in the $(ROOT)/doc directory, run make with no
+// target there if the PDF file isn't present.) If not, see
+// for a copy.
+//
+// License: GPL, v3, as defined and found on www.gnu.org,
+// http://www.gnu.org/licenses/gpl.html
+//
+//
+///////////////////////////////////////////////////////////////////////////
+#ifndef QSPIFLASHSIM_H
+#define QSPIFLASHSIM_H
+
+#define QSPIF_WIP_FLAG 0x0001
+#define QSPIF_WEL_FLAG 0x0002
+#define QSPIF_DEEP_POWER_DOWN_FLAG 0x0200
+class QSPIFLASHSIM {
+ typedef enum {
+ QSPIF_IDLE,
+ QSPIF_QUAD_READ_IDLE,
+ QSPIF_RDSR,
+ QSPIF_RDCR,
+ QSPIF_WRSR,
+ QSPIF_CLSR,
+ QSPIF_RDID,
+ QSPIF_RELEASE,
+ QSPIF_FAST_READ,
+ QSPIF_QUAD_READ_CMD,
+ QSPIF_QUAD_READ,
+ QSPIF_SECTOR_ERASE,
+ QSPIF_PP,
+ QSPIF_QPP,
+ QSPIF_BULK_ERASE,
+ QSPIF_DEEP_POWER_DOWN,
+ QSPIF_INVALID
+ } QSPIF_STATE;
+
+ QSPIF_STATE m_state;
+ char *m_mem, *m_pmem;
+ int m_last_sck;
+ unsigned m_write_count, m_ireg, m_oreg, m_sreg, m_addr,
+ m_count, m_config, m_mode_byte, m_creg;
+ bool m_quad_mode, m_debug;
+
+public:
+ QSPIFLASHSIM(void);
+ void load(const char *fname);
+ void debug(const bool dbg) { m_debug = dbg; }
+ bool debug(void) const { return m_debug; }
+ int operator()(const int csn, const int sck, const int dat);
+};
+
+#endif
Index: trunk/bench/cpp/port.h
===================================================================
--- trunk/bench/cpp/port.h (nonexistent)
+++ trunk/bench/cpp/port.h (revision 4)
@@ -0,0 +1 @@
+link ../../sw/port.h
\ No newline at end of file
trunk/bench/cpp/port.h
Property changes :
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/bench/cpp/busmaster_tb.cpp
===================================================================
--- trunk/bench/cpp/busmaster_tb.cpp (nonexistent)
+++ trunk/bench/cpp/busmaster_tb.cpp (revision 4)
@@ -0,0 +1,217 @@
+//
+//
+// Filename: busmaster_tb.cpp
+//
+// Project: FPGA library development (XuLA2 development board)
+//
+// Purpose: This is piped version of the testbench for the busmaster
+// verilog code. The busmaster code is designed to be a complete
+// code set implementing all of the functionality of the XESS
+// XuLA2 development board. If done well, the programs talking to
+// this one should be able to talk to the board and apply the
+// same tests to the board itself.
+//
+// Creator: Dan Gisselquist
+// Gisselquist Tecnology, LLC
+//
+// Copyright: 2015
+//
+//
+#include
+#include
+
+#include "verilated.h"
+#include "Vbusmaster.h"
+
+#include "testb.h"
+// #include "twoc.h"
+#include "pipecmdr.h"
+#include "qspiflashsim.h"
+#include "sdramsim.h"
+
+#include "port.h"
+
+// Add a reset line, since Vbusmaster doesn't have one
+class Vbusmasterr : public Vbusmaster {
+public:
+ int i_rst;
+ virtual ~Vbusmasterr() {}
+};
+
+// No particular "parameters" need definition or redefinition here.
+class BUSMASTER_TB : public PIPECMDR {
+public:
+ unsigned long m_tx_busy_count;
+ QSPIFLASHSIM m_flash;
+ SDRAMSIM m_sdram;
+ unsigned m_last_led;
+ time_t m_start_time;
+
+ BUSMASTER_TB(void) : PIPECMDR(FPGAPORT) {
+ m_start_time = time(NULL);
+ }
+
+ void reset(void) {
+ m_core->i_clk = 1;
+ m_core->eval();
+ }
+
+ void tick(void) {
+ if ((m_tickcount & ((1<<28)-1))==0) {
+ double ticks_per_second = m_tickcount;
+ ticks_per_second /= (double)(time(NULL) - m_start_time);
+ printf(" ******** %.6f TICKS PER SECOND\n",
+ ticks_per_second);
+ }
+
+ // Set up the bus before any clock tick
+ m_core->i_clk = 1;
+ m_core->i_spi_miso = m_flash(m_core->o_sf_cs_n,
+ m_core->o_spi_sck,
+ m_core->o_spi_mosi)&0x02;
+ m_core->i_ram_data = m_sdram(1,
+ m_core->o_ram_cke, m_core->o_ram_cs_n,
+ m_core->o_ram_ras_n, m_core->o_ram_cas_n,
+ m_core->o_ram_we_n, m_core->o_ram_bs,
+ m_core->o_ram_addr, m_core->o_ram_drive_data,
+ m_core->o_ram_data);
+ PIPECMDR::tick();
+
+ bool writeout = false;
+ /*
+ if (m_core->v__DOT__runio__DOT__themouse__DOT__driver__DOT__rx_stb)
+ writeout = true;
+ else if (m_core->v__DOT__runio__DOT__themouse__DOT__driver__DOT__ps2iface__DOT__state != m_last_ps2_state)
+ writeout = true;
+ else if (m_core->v__DOT__runio__DOT__themouse__DOT__m_state != m_last_mouse_state)
+ writeout = true;
+ else if (m_core->i_ps2 != m_last_ps2)
+ writeout = true;
+ else if (m_core->o_ps2 != m_last_ops2)
+ writeout = true;
+ else if (m_core->v__DOT__runio__DOT__themouse__DOT__driver__DOT__ps2_perr)
+ writeout = true;
+ else if (m_core->v__DOT__runio__DOT__themouse__DOT__driver__DOT__ps2_ferr)
+ writeout = true;
+ */
+ // if ((m_core->v__DOT__genbus__DOT__runwb__DOT__o_wb_cyc)||(m_core->v__DOT__bus_cyc))
+ // writeout = true;
+ // else if (m_last_cyc)
+ // writeout = true;
+ if ((m_tickcount > 0x5010)&&(m_core->v__DOT__sdram__DOT__r_state != 0))
+ writeout = true;
+ else if ((m_core->v__DOT__dwb_cyc)&&((m_core->v__DOT__wb_stb)
+ ||(m_core->v__DOT__dwb_stall)
+ ||(m_core->v__DOT__dwb_ack)))
+ writeout = true;
+ else if (m_core->v__DOT__dwb_cyc)
+ writeout = true;
+ else if (m_core->v__DOT__sdram__DOT__need_refresh)
+ writeout = true;
+ else if ((m_core->v__DOT__wbu_cyc)&&((m_core->v__DOT__wbu_addr == 0x106)||(m_core->v__DOT__wbu_addr == 0x0107)))
+ writeout = true;
+ if (m_tickcount < 0x05010)
+ writeout = false;
+ if (writeout) {
+ printf("%08lx:", m_tickcount);
+
+ printf("(%d,%d->%d),(%d,%d->%d)|%c[%08x/%08x]@%08x %d%d%c",
+ m_core->v__DOT__wbu_cyc,
+ m_core->v__DOT__dwb_cyc, // was zip_cyc
+ m_core->v__DOT__wb_cyc,
+ //
+ m_core->v__DOT__wbu_stb,
+ // 0, // m_core->v__DOT__dwb_stb, // was zip_stb
+ m_core->v__DOT__zippy__DOT__thecpu__DOT__mem_stb_gbl,
+ m_core->v__DOT__wb_stb,
+ //
+ (m_core->v__DOT__wb_we)?'W':'R',
+ m_core->v__DOT__wb_data,
+ m_core->v__DOT__dwb_idata,
+ m_core->v__DOT__wb_addr,
+ m_core->v__DOT__dwb_ack,
+ m_core->v__DOT__dwb_stall,
+ (m_core->v__DOT__wb_err)?'E':'.');
+
+ printf("%c[%d%d%d%d,%d:%04x%c]@%06x(%d) ->%06x%c",
+ (m_core->v__DOT__sdram_sel)?'!':' ',
+ m_core->o_ram_cs_n, m_core->o_ram_ras_n,
+ m_core->o_ram_cas_n, m_core->o_ram_we_n,
+ m_core->o_ram_bs, m_core->o_ram_data,
+ (m_core->o_ram_drive_data)?'D':'-',
+ m_core->o_ram_addr,
+ (m_core->o_ram_addr>>10)&1,
+ m_core->i_ram_data,
+ (m_core->o_ram_drive_data)?'-':'V');
+
+ printf(" SD[%d,%d-%3x%d]",
+ m_core->v__DOT__sdram__DOT__r_state,
+ m_sdram.pwrup(),
+ m_core->v__DOT__sdram__DOT__refresh_clk,
+ m_core->v__DOT__sdram__DOT__need_refresh);
+
+ printf(" BNK[%d:%6x,%d:%6x,%d:%6x,%d:%6x],%x%d",
+ m_core->v__DOT__sdram__DOT__bank_active[0],
+ m_core->v__DOT__sdram__DOT__bank_row[0],
+ m_core->v__DOT__sdram__DOT__bank_active[1],
+ m_core->v__DOT__sdram__DOT__bank_row[1],
+ m_core->v__DOT__sdram__DOT__bank_active[2],
+ m_core->v__DOT__sdram__DOT__bank_row[2],
+ m_core->v__DOT__sdram__DOT__bank_active[3],
+ m_core->v__DOT__sdram__DOT__bank_row[3],
+ m_core->v__DOT__sdram__DOT__clocks_til_idle,
+ m_core->v__DOT__sdram__DOT__r_barrell_ack);
+
+ printf(" %s%s%c[%08x@%06x]",
+ (m_core->v__DOT__sdram__DOT__bus_cyc)?"C":" ",
+ (m_core->v__DOT__sdram__DOT__r_pending)?"PND":" ",
+ (m_core->v__DOT__sdram__DOT__r_we)?'W':'R',
+ (m_core->v__DOT__sdram__DOT__r_data),
+ (m_core->v__DOT__sdram__DOT__r_addr));
+
+ printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%2x",
+ (m_core->v__DOT__zippy__DOT__dbg_ack)?"A":"-",
+ (m_core->v__DOT__zippy__DOT__dbg_stall)?"S":"-",
+ (m_core->v__DOT__zippy__DOT__sys_dbg_cyc)?"D":"-",
+ (m_core->v__DOT__zippy__DOT__cpu_lcl_cyc)?"L":"-",
+ (m_core->v__DOT__zippy__DOT__cpu_dbg_stall)?"Z":"-",
+ (m_core->v__DOT__zippy__DOT__cmd_halt)?"H":"-",
+ (m_core->v__DOT__zippy__DOT__thecpu__DOT__pf_cyc)?"P":"-",
+ (m_core->v__DOT__zippy__DOT__thecpu__DOT__mem_cyc_gbl)?"G":"-",
+ (m_core->v__DOT__zippy__DOT__thecpu__DOT__mem_cyc_lcl)?"L":"-",
+ (m_core->v__DOT__zippy__DOT__thecpu__DOT__dcdvalid)?"D":"-",
+ (m_core->v__DOT__zippy__DOT__thecpu__DOT__dcd_ce)?"k":"-",
+ (m_core->v__DOT__zippy__DOT__thecpu__DOT__opvalid)?"O":"-",
+ (m_core->v__DOT__zippy__DOT__thecpu__DOT__op_ce)?"k":"-",
+ (m_core->v__DOT__zippy__DOT__thecpu__DOT__new_pc)?"N":"-",
+ (m_core->v__DOT__zippy__DOT__thecpu__DOT__clear_pipeline)?"C":"-",
+ (m_core->v__DOT__zippy__DOT__cmd_addr));
+
+ printf("\n");
+ }
+
+ }
+
+};
+
+BUSMASTER_TB *tb;
+
+void busmaster_kill(int v) {
+ tb->kill();
+ exit(0);
+}
+
+int main(int argc, char **argv) {
+ Verilated::commandArgs(argc, argv);
+ tb = new BUSMASTER_TB;
+
+ // signal(SIGINT, busmaster_kill);
+
+ tb->reset();
+
+ while(1)
+ tb->tick();
+
+ exit(0);
+}
+
Index: trunk/bench/cpp/Makefile
===================================================================
--- trunk/bench/cpp/Makefile (nonexistent)
+++ trunk/bench/cpp/Makefile (revision 4)
@@ -0,0 +1,43 @@
+.PHONY: all
+CXX := g++
+OBJDIR := obj-pc
+YYMMDD := `date +%Y%m%d`
+VOBJDR := ../../rtl/obj_dir
+VROOT := /usr/share/verilator
+VINC := -I$(VROOT)/include -I$(VOBJDR)
+CFLAGS := -c -g -Wall -I. $(VINC)
+#
+all: $(OBJDIR)/ programs archive
+
+# GFXFLAGS := `pkg-config gtkmm-3.0 --cflags`
+# GFXLIBS := `pkg-config gtkmm-3.0 --cflags --libs`
+
+.PHONY: programs
+programs: busmaster_tb
+
+.PHONY: clean
+clean:
+ rm -f busmaster_rb $(OBJDIR)/*.o
+
+$(OBJDIR)/:
+ @bash -c "if [ ! -e $(OBJDIR) ]; then mkdir -p $(OBJDIR); fi"
+
+$(OBJDIR)/sdramsim.o: sdramsim.cpp sdramsim.h
+ $(CXX) $(CFLAGS) $< -o $@
+$(OBJDIR)/qspiflashsim.o: qspiflashsim.cpp qspiflashsim.h
+ $(CXX) $(CFLAGS) $< -o $@
+$(OBJDIR)/busmaster_tb.o: busmaster_tb.cpp pipecmdr.h sdramsim.h
+$(OBJDIR)/busmaster_tb.o: port.h $(VOBJDR)/Vbusmaster.h
+ $(CXX) $(CFLAGS) busmaster_tb.cpp -o $@
+$(OBJDIR)/verilated.o: $(VROOT)/include/verilated.cpp
+ $(CXX) $(CFLAGS) $< -o $@
+
+busmaster_tb: $(OBJDIR)/qspiflashsim.o
+busmaster_tb: $(OBJDIR)/verilated.o
+busmaster_tb: $(VOBJDR)/Vbusmaster__ALL.a
+busmaster_tb: $(OBJDIR)/busmaster_tb.o $(OBJDIR)/sdramsim.o
+ $(CXX) -g -o $@ $^
+
+.PHONY: archive
+archive:
+ tar --transform s,^,$(YYMMDD)-bench-cpp/, -chjf $(YYMMDD)-bench-cpp.tjz Makefile *.cpp *.h