URL
https://opencores.org/ocsvn/s6soc/s6soc/trunk
Subversion Repositories s6soc
Compare Revisions
- This comparison shows the changes necessary to convert path
/s6soc/trunk
- from Rev 10 to Rev 11
- ↔ Reverse comparison
Rev 10 → Rev 11
/rtl/deppbyte.v
0,0 → 1,135
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: deppbyte.v |
// |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
// Purpose: This is a very simple DEPP to synchronous byte transfer. It |
// is used in place of a serial port. |
// |
// This approach uses address zero *only*. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, 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 |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
module deppbyte(i_clk, |
i_astb_n, i_dstb_n, i_write_n,i_depp, o_depp, o_wait, |
o_rx_stb, o_rx_data, |
i_tx_stb, i_tx_data, o_tx_busy); |
input i_clk; |
// DEPP interface |
input i_astb_n, i_dstb_n, i_write_n; |
input [7:0] i_depp; |
output reg [7:0] o_depp; |
output wire o_wait; |
// Byte-wise interface to the rest of the world |
output reg o_rx_stb; |
output reg [7:0] o_rx_data; |
input i_tx_stb; |
input [7:0] i_tx_data; |
output reg o_tx_busy; |
|
// Synchronize the incoming signals |
reg x_dstb_n, x_astb_n, x_write_n, |
r_dstb_n, r_astb_n, r_write_n, |
l_dstb_n, l_astb_n, l_write_n; |
reg [7:0] x_depp, r_depp; |
initial x_dstb_n = 1'b1; |
initial r_dstb_n = 1'b1; |
initial l_dstb_n = 1'b1; |
initial x_astb_n = 1'b1; |
initial r_astb_n = 1'b1; |
initial l_astb_n = 1'b1; |
always @(posedge i_clk) |
begin |
{ x_dstb_n, x_astb_n, x_write_n, x_depp } |
<= { i_dstb_n, i_astb_n, i_write_n, i_depp }; |
{ r_dstb_n, r_astb_n, r_write_n, r_depp } |
<= { x_dstb_n, x_astb_n, x_write_n, x_depp }; |
{ l_dstb_n, l_astb_n, l_write_n } <= { r_dstb_n, r_astb_n, r_write_n }; |
end |
|
reg [7:0] addr; |
wire astb, dstb, w_write; |
assign astb = (~r_astb_n)&&(l_astb_n); |
assign dstb = (~r_dstb_n)&&(l_dstb_n); |
assign w_write= (~r_write_n); |
|
|
initial addr = 8'h00; |
initial o_rx_stb = 1'b0; |
always @(posedge i_clk) |
begin |
if ((w_write)&&(astb)) |
addr <= r_depp; |
|
if ((w_write)&&(dstb)&&(addr==0)) |
begin |
o_rx_stb <= 1'b1; |
o_rx_data <= r_depp; |
end else |
o_rx_stb <= 1'b0; |
end |
|
// Much as I hate to use signals that have not been synchronized with a |
// two clock transfer, this line needs to be brought low within 10ms |
// (less than one clock) of when the strobe lines are brought low, and |
// raised high again within 10 ms of when the strobe lines are raised |
// again. |
assign o_wait = ((~i_dstb_n)||(~i_astb_n)); |
|
// For one clock, following any read from address zero, we allow the |
// port to write one new byte into our interface. This works because |
// the interface will guarantee that the strobe signals are inactive |
// (high) for at least 40ns before attempting a new transaction. |
// |
// Just about nothing else works. 'cause we can't allow changes |
// in the middle of a transaction, and we won't know if the clock |
// involved is in the middle of a transaction until after the time |
// has passed. Therefore, we're going to be busy most of the time |
// and just allow a byte to pass through on the one (and only) clock |
// following a transaction. |
always @(posedge i_clk) |
o_tx_busy <= ((~l_dstb_n)&&(r_dstb_n)&&(l_write_n)&&(addr == 0)) |
? 1'b0 : 1'b1; |
|
// If we don't have a byte to write, stuff it with all ones. The high |
// bit will then indicate that there's nothing available to the |
// interface when it next reads. |
// |
// Okay, new philosophy. Stuff the high bit with ones, allow the other |
// bits to contain status level information --- should any one wish to |
// send such. |
initial o_depp = 8'hff; |
always @(posedge i_clk) |
if (~o_tx_busy) |
o_depp <= {((i_tx_stb)? i_tx_data[7] : 1'b1), |
i_tx_data[6:0] }; |
|
endmodule |
/rtl/wbqspiflash.v
65,10 → 65,10
`define WBQSPI_READ_CMD 8 |
`define WBQSPI_READ_DATA 9 |
`define WBQSPI_WAIT_TIL_RDIDLE 10 |
`define WBQSPI_READ_ID_CMD 11 |
`define WBQSPI_READ_ID 12 |
`define WBQSPI_READ_STATUS 13 |
`define WBQSPI_READ_CONFIG 14 |
`define WBQSPI_READ_ID_CMD 11 // |
`define WBQSPI_READ_ID 12 // |
`define WBQSPI_READ_STATUS 13 // |
`define WBQSPI_READ_CONFIG 14 // |
`define WBQSPI_WAIT_TIL_IDLE 15 |
// |
// |
147,6 → 147,7
end |
|
reg [7:0] last_status; |
reg [9:0] reset_counter; |
reg quad_mode_enabled; |
reg spif_cmd, spif_override; |
reg [(ADDRESS_WIDTH-3):0] spif_addr; |
153,6 → 154,7
reg [31:0] spif_data; |
reg [5:0] state; |
reg spif_ctrl, spif_req; |
reg alt_cmd, alt_ctrl; |
wire [(ADDRESS_WIDTH-17):0] spif_sector; |
assign spif_sector = spif_addr[(ADDRESS_WIDTH-3):14]; |
|
165,9 → 167,12
initial spi_len = 2'b00; |
initial quad_mode_enabled = 1'b0; |
initial o_interrupt = 1'b0; |
initial spif_override = 1'b1; |
always @(posedge i_clk_100mhz) |
begin |
spif_override <= 1'b0; |
alt_cmd <= (reset_counter[9:8]==2'b10)?reset_counter[3]:1'b1; // Toggle CS_n |
alt_ctrl <= (reset_counter[9:8]==2'b10)?reset_counter[0]:1'b1; // Toggle clock too |
if (state == `WBQSPI_RESET) |
begin |
// From a reset, we should |
185,7 → 190,8
state <= `WBQSPI_RESET_QUADMODE; |
spif_req <= 1'b0; |
spif_override <= 1'b1; |
last_status <= 8'hfc; // |
last_status <= 8'h00; // |
reset_counter <= 10'h3fc; // |
// This guarantees that we aren't starting in quad |
// I/O mode, where the FPGA configuration scripts may |
// have left us. |
193,21 → 199,28
begin |
// Okay, so here's the problem: we don't know whether or not |
// the Xilinx loader started us up in Quad Read I/O idle mode. |
// So, thus we need to |
// So, thus we need to toggle the clock and CS_n, with fewer |
// clocks than are necessary to transmit a word. |
// |
// Not ready to handle the bus yet, so stall any requests |
o_wb_ack <= 1'b0; |
o_wb_stall <= 1'b1; |
|
// Do something ... |
if (last_status == 8'h00) |
if (reset_counter == 10'h00) |
begin |
spif_override <= 1'b0; |
state <= `WBQSPI_IDLE; |
|
// Find out if we can use Quad I/O mode ... |
state <= `WBQSPI_READ_CONFIG; |
spi_wr <= 1'b1; |
spi_len <= 2'b01; |
spi_in <= { 8'h35, 24'h00}; |
|
end else begin |
last_status <= last_status - 8'h1; |
reset_counter <= reset_counter - 10'h1; |
spif_override <= 1'b1; |
spif_cmd <= last_status[3]; // Toggle CS_n |
spif_ctrl <= last_status[0]; // Toggle clock too |
end |
end else if (state == `WBQSPI_IDLE) |
begin |
1184,8 → 1197,8
end |
|
// Command and control during the reset sequence |
assign o_qspi_cs_n = (spif_override)?spif_cmd :w_qspi_cs_n; |
assign o_qspi_sck = (spif_override)?spif_ctrl:w_qspi_sck; |
assign o_qspi_mod = (spif_override)? 2'b01 :w_qspi_mod; |
assign o_qspi_dat = (spif_override)? 4'b00 :w_qspi_dat; |
assign o_qspi_cs_n = (spif_override)?alt_cmd :w_qspi_cs_n; |
assign o_qspi_sck = (spif_override)?alt_ctrl:w_qspi_sck; |
assign o_qspi_mod = (spif_override)? 2'b01 :w_qspi_mod; |
assign o_qspi_dat = (spif_override)? 4'b00 :w_qspi_dat; |
endmodule |
/rtl/cpu/idecode.v
75,21 → 75,25
output reg [3:0] o_cond; |
output reg o_wF; |
output reg [3:0] o_op; |
output reg o_ALU, o_M, o_DV, o_FP, o_break, o_lock; |
output reg o_ALU, o_M, o_DV, o_FP, o_break; |
output wire o_lock; |
output reg o_wR, o_rA, o_rB; |
output wire o_early_branch; |
output wire [(AW-1):0] o_branch_pc; |
output wire o_ljmp; |
output reg o_pipe; |
output wire o_pipe; |
|
wire dcdA_stall, dcdB_stall, dcdF_stall; |
wire o_dcd_early_branch; |
wire [(AW-1):0] o_dcd_branch_pc; |
reg o_dcdI, o_dcdIz; |
`ifdef OPT_PIPELINED |
reg r_lock, r_pipe; |
`endif |
|
|
wire [4:0] w_op; |
wire w_ldi, w_mov, w_cmptst, w_ldixx, w_ALU; |
wire w_ldi, w_mov, w_cmptst, w_ldilo, w_ALU, w_brev, w_noop; |
wire [4:0] w_dcdR, w_dcdB, w_dcdA; |
wire w_dcdR_pc, w_dcdR_cc; |
wire w_dcdA_pc, w_dcdA_cc; |
98,16 → 102,9
wire w_wF, w_dcdM, w_dcdDV, w_dcdFP; |
wire w_wR, w_rA, w_rB, w_wR_n; |
wire w_ljmp; |
wire [31:0] iword; |
|
generate |
if (EARLY_BRANCHING != 0) |
assign w_ljmp = (iword == 32'h7c87c000); |
else |
assign w_ljmp = 1'b0; |
endgenerate |
|
|
wire [31:0] iword; |
`ifdef OPT_VLIW |
reg [16:0] r_nxt_half; |
assign iword = (o_phase) |
119,16 → 116,37
assign iword = { 1'b0, i_instruction[30:0] }; |
`endif |
|
generate |
if (EARLY_BRANCHING != 0) |
assign w_ljmp = (iword == 32'h7c87c000); |
else |
assign w_ljmp = 1'b0; |
endgenerate |
|
|
assign w_op= iword[26:22]; |
assign w_mov = (w_op == 5'h0f); |
assign w_ldi = (w_op[4:1] == 4'hb); |
assign w_brev = (w_op == 5'hc); |
assign w_cmptst = (w_op[4:1] == 4'h8); |
assign w_ldixx = (w_op[4:1] == 4'h4); |
assign w_ldilo = (w_op[4:0] == 5'h9); |
assign w_ALU = (~w_op[4]); |
|
// 4 LUTs |
// |
// Two parts to the result register: the register set, given for |
// moves in i_word[18] but only for the supervisor, and the other |
// four bits encoded in the instruction. |
// |
assign w_dcdR = { ((~iword[31])&&(w_mov)&&(~i_gie))?iword[18]:i_gie, |
iword[30:27] }; |
// 2 LUTs |
// |
// If the result register is either CC or PC, and this would otherwise |
// be a floating point instruction with floating point opcode of 0, |
// then this is a NOOP. |
assign w_noop = (w_op[4:0] == 5'h18)&&(w_dcdR[3:1] == 3'h7); |
|
// 4 LUTs |
assign w_dcdB = { ((~iword[31])&&(w_mov)&&(~i_gie))?iword[13]:i_gie, |
iword[17:14] }; |
175,7 → 193,7
||(w_op[4:1]== 4'h8); |
// 1 LUTs -- do we read a register for operand B? Specifically, do |
// we need to stall if the register is not (yet) ready? |
assign w_rB = (w_mov)||((iword[18])&&((~w_ldi)&&(~w_ldixx))); |
assign w_rB = (w_mov)||((iword[18])&&(~w_ldi)); |
// 1 LUT: All but STO, NOOP/BREAK/LOCK, and CMP/TST write back to w_dcdR |
assign w_wR_n = ((w_dcdM)&&(w_op[0])) |
||((w_op[4:3]==2'b11)&&(w_dcdR[3:1]==3'h7)) |
188,7 → 206,7
// and writes to the PC/CC register(s). |
assign w_wF = (w_cmptst) |
||((w_cond[3])&&((w_dcdFP)||(w_dcdDV) |
||((w_ALU)&&(~w_mov)&&(~w_ldixx) |
||((w_ALU)&&(~w_mov)&&(~w_ldilo)&&(~w_brev) |
&&(iword[30:28] != 3'h7)))); |
|
// Bottom 13 bits: no LUT's |
271,8 → 289,10
|
if ((w_op[4:3]==2'b11)&&(w_dcdR[3:1]==3'h7) |
&&( |
(w_op[2:0] != 3'h2) // LOCK |
&&(w_op[2:0] != 3'h1) // BREAK |
(w_op[2:0] != 3'h1) // BREAK |
`ifdef OPT_PIPELINED |
&&(w_op[2:0] != 3'h2) // LOCK |
`endif |
&&(w_op[2:0] != 3'h0))) // NOOP |
o_illegal <= 1'b1; |
end |
313,7 → 333,7
// o_FP plus these four bits uniquely defines the FP |
// instruction, o_DV plus the bottom of these defines |
// the divide, etc. |
o_op <= (w_ldi)? 4'hf:w_op[3:0]; |
o_op <= (w_ldi)||(w_noop)? 4'hf:w_op[3:0]; |
|
// Default values |
o_dcdR <= { w_dcdR_cc, w_dcdR_pc, w_dcdR}; |
325,13 → 345,20
r_I <= w_I; |
o_zI <= w_Iz; |
|
o_ALU <= (w_ALU)||(w_ldi)||(w_cmptst); // 1 LUT |
// Turn a NOOP into an ALU operation--subtract in |
// particular, although it doesn't really matter as long |
// as it doesn't take longer than one clock. Note |
// also that this depends upon not setting any registers |
// or flags, which should already be true. |
o_ALU <= (w_ALU)||(w_ldi)||(w_cmptst)||(w_noop); // 2 LUT |
o_M <= w_dcdM; |
o_DV <= w_dcdDV; |
o_FP <= w_dcdFP; |
|
o_break <= (w_op[4:3]==2'b11)&&(w_dcdR[3:1]==3'h7)&&(w_op[2:0]==3'b001); |
o_lock <= (w_op[4:3]==2'b11)&&(w_dcdR[3:1]==3'h7)&&(w_op[2:0]==3'b010); |
`ifdef OPT_PIPELINED |
r_lock <= (w_op[4:3]==2'b11)&&(w_dcdR[3:1]==3'h7)&&(w_op[2:0]==3'b010); |
`endif |
`ifdef OPT_VLIW |
r_nxt_half <= { iword[31], iword[13:5], |
((iword[21])? iword[20:19] : 2'h0), |
339,6 → 366,12
`endif |
end |
|
`ifdef OPT_PIPELINED |
assign o_lock = r_lock; |
`else |
assign o_lock = 1'b0; |
`endif |
|
generate |
if (EARLY_BRANCHING!=0) |
begin |
410,16 → 443,25
// taking place, and it's only valid if the new word is not compressed. |
// |
reg r_valid; |
`ifdef OPT_PIPELINED |
reg r_pipe; |
initial r_pipe = 1'b0; |
always @(posedge i_clk) |
if (i_ce) |
o_pipe <= (r_valid)&&(i_pf_valid)&&(~i_instruction[31]) |
r_pipe <= (r_valid)&&(i_pf_valid)&&(~i_instruction[31]) |
&&(w_dcdM)&&(o_M)&&(o_op[0] ==i_instruction[22]) |
&&(i_instruction[17:14] == o_dcdB[3:0]) |
&&(i_instruction[17:14] != o_dcdA[3:0]) |
&&(i_gie == o_gie) |
&&((i_instruction[21:19]==o_cond[2:0]) |
||(o_cond[2:0] == 3'h0)) |
&&((i_instruction[13:0]==r_I[13:0]) |
||({1'b0, i_instruction[13:0]}==(r_I[13:0]+14'h1))); |
assign o_pipe = r_pipe; |
`else |
assign o_pipe = 1'b0; |
`endif |
|
always @(posedge i_clk) |
if (i_rst) |
r_valid <= 1'b0; |
/rtl/cpu/zipcpu.v
869,10 → 869,8
always @(posedge i_clk) |
if (i_rst) |
r_op_lock <= 1'b0; |
else if ((op_ce)&&(dcd_lock)) |
r_op_lock <= 1'b1; |
else if ((op_ce)||(clear_pipeline)) |
r_op_lock <= 1'b0; |
else if (op_ce) |
r_op_lock <= (dcd_lock)&&(~clear_pipeline); |
assign op_lock = r_op_lock; |
|
end else begin |
1180,16 → 1178,16
generate |
if (IMPLEMENT_LOCK != 0) |
begin |
reg r_bus_lock; |
initial r_bus_lock = 1'b0; |
reg [1:0] r_bus_lock; |
initial r_bus_lock = 2'b00; |
always @(posedge i_clk) |
if (i_rst) |
r_bus_lock <= 1'b0; |
r_bus_lock <= 2'b00; |
else if ((op_ce)&&(op_lock)) |
r_bus_lock <= 1'b1; |
else if (~opvalid_mem) |
r_bus_lock <= 1'b0; |
assign bus_lock = r_bus_lock; |
r_bus_lock <= 2'b11; |
else if ((|r_bus_lock)&&((~opvalid_mem)||(~op_ce))) |
r_bus_lock <= r_bus_lock + 2'b11; |
assign bus_lock = |r_bus_lock; |
end else begin |
assign bus_lock = 1'b0; |
end endgenerate |
1640,7 → 1638,7
else if ((new_pc)||((~dcd_stalled)&&(pf_valid))) |
pf_pc <= pf_pc + {{(AW-1){1'b0}},1'b1}; |
`else |
else if ((alu_pc_valid)&&(~clear_pipeline)) |
else if (((alu_pc_valid)&&(~clear_pipeline))||(mem_pc_valid)) |
pf_pc <= alu_pc; |
`endif |
|
/rtl/builddate.v
1,7 → 1638,7
`define DATESTAMP 32'h20160423 |
`define DATESTAMP 32'h20160428 |
/rtl/busmaster.v
60,7 → 60,7
// GPIO lines |
i_gpio, o_gpio); |
parameter BUS_ADDRESS_WIDTH=23, ZIP_ADDRESS_WIDTH=BUS_ADDRESS_WIDTH, |
CMOD_ZIPCPU_RESET_ADDRESS=23'h400100, |
CMOD_ZIPCPU_RESET_ADDRESS=23'h480000, |
ZA=ZIP_ADDRESS_WIDTH, BAW=BUS_ADDRESS_WIDTH; // 24bits->2,258,23b->2181 |
input i_clk, i_rst; |
input i_rx_stb; |
222,8 → 222,9
assign many_sel =((wb_cyc)&&(wb_stb)&&( |
{3'h0, io_sel} |
+{3'h0, flctl_sel} |
// +{3'h0, scop_sel} |
+{3'h0, scop_sel} |
+{3'h0, cfg_sel} |
+{3'h0, rtc_sel} |
+{3'h0, mem_sel} |
+{3'h0, flash_sel} > 1)); |
*/ |
264,14 → 265,14
if (wb_err) |
bus_err_addr <= wb_addr; |
|
wire [31:0] timer_a, timer_b; |
wire zta_ack, zta_stall, ztb_ack, ztb_stall; |
wire [31:0] timer_a, timer_b; |
ziptimer #(32,20) |
ziptimer #(32,31) |
zipt_a(i_clk, 1'b0, 1'b1, wb_cyc, |
(wb_stb)&&(io_sel)&&(wb_addr[3:0]==4'h2), |
wb_we, wb_data, zta_ack, zta_stall, timer_a, |
tmra_int); |
ziptimer #(32,20) |
ziptimer #(32,31) |
zipt_b(i_clk, 1'b0, 1'b1, wb_cyc, |
(wb_stb)&&(io_sel)&&(wb_addr[3:0]==4'h3), |
wb_we, wb_data, ztb_ack, ztb_stall, timer_b, |
389,9 → 390,8
// |
// FLASH MEMORY CONFIGURATION ACCESS |
// |
wire flash_cs_n, flash_sck, flash_mosi; |
wbqspiflash #(24) flashmem(i_clk, |
wb_cyc,(wb_stb&&flash_sel),(wb_stb)&&(flctl_sel),wb_we, |
wb_cyc,(wb_stb)&&(flash_sel),(wb_stb)&&(flctl_sel),wb_we, |
wb_addr[(24-3):0], wb_data, |
flash_ack, flash_stall, flash_data, |
o_qspi_sck, o_qspi_cs_n, o_qspi_mod, o_qspi_dat, i_qspi_dat, |
/rtl/altbusmaster.v
38,7 → 38,7
// |
`include "builddate.v" |
// |
`define IMPLEMENT_ONCHIP_RAM |
// `define IMPLEMENT_ONCHIP_RAM |
`ifndef VERILATOR |
`define FANCY_ICAP_ACCESS |
`endif |
45,6 → 45,7
`define FLASH_ACCESS |
`define DBG_SCOPE // About 204 LUTs, at 2^6 addresses |
`define INCLUDE_RTC // About 90 LUTs |
`define WBUBUS |
module altbusmaster(i_clk, i_rst, |
// DEPP I/O Control |
i_depp_astb_n, i_depp_dstb_n, i_depp_write_n, |
123,14 → 124,26
// The BUS master (source): The WB to UART conversion bus |
// |
// |
wbubus busbdriver(i_clk, i_rx_stb, i_rx_data, |
wire dep_rx_stb, dep_tx_stb, dep_tx_busy; |
wire [7:0] dep_rx_data, dep_tx_data; |
deppbyte deppdrive(i_clk, |
i_depp_astb_n, i_depp_dstb_n, i_depp_write_n, |
i_depp_data, o_depp_data, o_depp_wait, |
dep_rx_stb, dep_rx_data, |
dep_tx_stb, dep_tx_data, dep_tx_busy); |
|
wbubus busbdriver(i_clk, |
// i_rx_stb, i_rx_data, // UART control |
dep_rx_stb, dep_rx_data, // DEPP control |
// The wishbone interface |
wb_cyc, wb_stb, wb_we, w_wbu_addr, wb_data, |
wb_ack, wb_stall, wb_err, wb_idata, |
w_interrupt, |
// Provide feedback to the UART |
o_tx_stb, o_tx_data, i_tx_busy); |
assign o_uart_rts = (~rx_rdy); |
// Provide feedback to the DEPP interface |
dep_tx_stb, dep_tx_data, dep_tx_busy); |
// // Provide feedback to the UART |
// o_tx_stb, o_tx_data, i_tx_busy |
// assign o_uart_rts = (~rx_rdy); |
`else |
// |
// |
239,14 → 252,14
// |
// |
reg rx_rdy; |
wire [10:0] int_vector; |
assign int_vector = { gpio_int, pwm_int, keypad_int, |
wire [11:0] int_vector; |
assign int_vector = { flash_interrupt, gpio_int, pwm_int, keypad_int, |
~i_tx_busy, rx_rdy, tmrb_int, tmra_int, |
rtc_interrupt, scop_interrupt, |
wb_err, button_int }; |
|
wire [31:0] pic_data; |
icontrol #(11) pic(i_clk, 1'b0, (wb_stb)&&(io_sel) |
icontrol #(12) pic(i_clk, 1'b0, (wb_stb)&&(io_sel) |
&&(wb_addr[3:0]==4'h0)&&(wb_we), |
wb_data, pic_data, int_vector, w_interrupt); |
|
255,8 → 268,8
if (wb_err) |
bus_err_addr <= wb_addr; |
|
wire [31:0] timer_a, timer_b; |
wire zta_ack, zta_stall, ztb_ack, ztb_stall; |
wire [31:0] timer_a, timer_b; |
ziptimer #(32,20) |
zipt_a(i_clk, 1'b0, 1'b1, wb_cyc, |
(wb_stb)&&(io_sel)&&(wb_addr[3:0]==4'h2), |
380,9 → 393,8
// |
// FLASH MEMORY CONFIGURATION ACCESS |
// |
wire flash_cs_n, flash_sck, flash_mosi; |
wbqspiflashp #(24) flashmem(i_clk, |
wb_cyc,(wb_stb&&flash_sel),(wb_stb)&&(flctl_sel),wb_we, |
wb_cyc,(wb_stb)&&(flash_sel),(wb_stb)&&(flctl_sel),wb_we, |
wb_addr[(24-3):0], wb_data, |
flash_ack, flash_stall, flash_data, |
o_qspi_sck, o_qspi_cs_n, o_qspi_mod, o_qspi_dat, i_qspi_dat, |
/cmodtop.ucf
0,0 → 1,155
################################################################################ |
## |
## Filename: cmod.ucf |
## |
## Project: CMod S6 System on a Chip, ZipCPU demonstration project |
## |
## Purpose: This file is really from Digilent, and so the copyright |
## statement below applies only to those changes that have been |
## made to modify it to support the CMod S6 SoC project. That said ... |
## |
## This file specifies the pin connections for all of the peripherals |
## connected to the Cmod S6 SoC. |
## |
## Further, this file is *specific* to the main ZipCPU build. Apparently, |
## two top level files require two ucf files, so this file applies to the |
## main ZipCPU build, and the other file to the alternate, auxiliary build. |
## |
## |
## Creator: Dan Gisselquist, Ph.D. |
## Gisselquist Technology, LLC |
## |
################################################################################ |
## |
## Copyright (C) 2015-2016, 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 |
## |
## |
################################################################################ |
## |
## |
|
#FPGA_GCLK |
NET "i_clk_8mhz" LOC = "N8" | IOSTANDARD = LVCMOS33; |
NET "i_clk_8mhz" TNM_NET = "i_clk_8mhz"; |
TIMESPEC "TSi_clk_8mhz" = PERIOD "i_clk_8mhz" 125.0 ns HIGH 50%; |
|
#CLK_LFC |
# NET "i_clk_pps" LOC = "N7" | IOSTANDARD = LVCMOS33; |
|
#BTNs |
NET "i_btn<0>" LOC = "P8" | IOSTANDARD = LVCMOS33; |
NET "i_btn<1>" LOC = "P9" | IOSTANDARD = LVCMOS33; |
|
#LEDs |
NET "o_led<0>" LOC = "N3" | IOSTANDARD = LVCMOS33; |
NET "o_led<1>" LOC = "P3" | IOSTANDARD = LVCMOS33; |
NET "o_led<2>" LOC = "N4" | IOSTANDARD = LVCMOS33; |
NET "o_led<3>" LOC = "P4" | IOSTANDARD = LVCMOS33; |
|
# Flash |
NET "o_qspi_sck" LOC="N13" | IOSTANDARD = LVCMOS33; |
NET "o_qspi_cs_n" LOC="P2" | IOSTANDARD = LVCMOS33; |
NET "io_qspi_dat<0>" LOC="P11" | IOSTANDARD = LVCMOS33; |
NET "io_qspi_dat<1>" LOC="N11" | IOSTANDARD = LVCMOS33; |
NET "io_qspi_dat<2>" LOC="N10" | IOSTANDARD = LVCMOS33; |
NET "io_qspi_dat<3>" LOC="P10" | IOSTANDARD = LVCMOS33; |
|
#DEPP Signals |
# NET "o_depp_wait" LOC = "B6" | IOSTANDARD = LVCMOS33; |
# NET "i_depp_astb_n" LOC = "A6" | IOSTANDARD = LVCMOS33; |
# NET "i_depp_dstb_n" LOC = "B7" | IOSTANDARD = LVCMOS33; |
# NET "i_depp_write_n" LOC = "A7" | IOSTANDARD = LVCMOS33; |
# NET "io_depp_data<0>" LOC = "B9" | IOSTANDARD = LVCMOS33; |
# NET "io_depp_data<1>" LOC = "A9" | IOSTANDARD = LVCMOS33; |
# NET "io_depp_data<2>" LOC = "B10" | IOSTANDARD = LVCMOS33; |
# NET "io_depp_data<3>" LOC = "A10" | IOSTANDARD = LVCMOS33; |
# NET "io_depp_data<4>" LOC = "B11" | IOSTANDARD = LVCMOS33; |
# NET "io_depp_data<5>" LOC = "A11" | IOSTANDARD = LVCMOS33; |
# NET "io_depp_data<6>" LOC = "B12" | IOSTANDARD = LVCMOS33; |
# NET "io_depp_data<7>" LOC = "A12" | IOSTANDARD = LVCMOS33; |
|
#IO PORTs |
|
# UART: PIO26 (CTS), PIO27 (TXD), PIO28(RXD), PIO29(RTS) |
NET "i_uart" LOC = "A2" | IOSTANDARD = LVCMOS33; |
NET "o_uart" LOC = "B3" | IOSTANDARD = LVCMOS33; |
NET "i_uart_cts" LOC = "A3" | IOSTANDARD = LVCMOS33; |
NET "o_uart_rts" LOC = "B1" | IOSTANDARD = LVCMOS33; |
# PWM-Audio: Shutdown (PIO46), Gain (PIO47), PWM-Audio (PIO48) |
NET "o_pwm" LOC = "M2" | IOSTANDARD = LVCMOS33; |
NET "o_pwm_shutdown_n" LOC = "L2" | IOSTANDARD = LVCMOS33 | PULLUP; |
NET "o_pwm_gain" LOC = "M1" | IOSTANDARD = LVCMOS33 | PULLUP; |
# I2C |
NET "io_scl" LOC = "E14" | IOSTANDARD = LVCMOS33 | PULLUP; # io_scl, PIO44 |
NET "io_sda" LOC = "G13" | IOSTANDARD = LVCMOS33 | PULLUP; # io_sda, PIO45 |
|
# |
# o_gpio<0> and o_gpio<1> have been borrowed for io_scl and io_sda, hence we |
# start our count here at 2 |
# |
# NET "o_gpio<0>" LOC = "G13" | IOSTANDARD = LVCMOS33; # io_sda |
# NET "o_gpio<1>" LOC = "E14" | IOSTANDARD = LVCMOS33; # io_scl |
NET "o_gpio<2>" LOC = "D13" | IOSTANDARD = LVCMOS33; # display o_mosi |
NET "o_gpio<3>" LOC = "E13" | IOSTANDARD = LVCMOS33; # display o_sck |
NET "o_gpio<4>" LOC = "C13" | IOSTANDARD = LVCMOS33; # display o_ss |
NET "o_gpio<5>" LOC = "G14" | IOSTANDARD = LVCMOS33; |
NET "o_gpio<6>" LOC = "F13" | IOSTANDARD = LVCMOS33; |
NET "o_gpio<7>" LOC = "F14" | IOSTANDARD = LVCMOS33; |
NET "o_gpio<8>" LOC = "H13" | IOSTANDARD = LVCMOS33; |
NET "o_gpio<9>" LOC = "H14" | IOSTANDARD = LVCMOS33; |
NET "o_gpio<10>" LOC = "J13" | IOSTANDARD = LVCMOS33; |
NET "o_gpio<11>" LOC = "J14" | IOSTANDARD = LVCMOS33; |
NET "o_gpio<12>" LOC = "C1" | IOSTANDARD = LVCMOS33; |
NET "o_gpio<13>" LOC = "D1" | IOSTANDARD = LVCMOS33; |
NET "o_gpio<14>" LOC = "D2" | IOSTANDARD = LVCMOS33; |
NET "o_gpio<15>" LOC = "E1" | IOSTANDARD = LVCMOS33; |
|
# |
# As with the o_gpio wires, i_gpio<0> and i_gpio<1> have been borrowed for |
# io_scl and io_sda, hence we start our count here at 2 |
# |
# NET "i_gpio<0>" LOC = "G13" | IOSTANDARD = LVCMOS33; # io_sda |
# NET "i_gpio<1>" LOC = "E14" | IOSTANDARD = LVCMOS33; # io_scl |
NET "i_gpio<2>" LOC = "D14" | IOSTANDARD = LVCMOS33; # display miso |
NET "i_gpio<3>" LOC = "E2" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<4>" LOC = "F1" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<5>" LOC = "F2" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<6>" LOC = "H1" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<7>" LOC = "H2" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<8>" LOC = "G1" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<9>" LOC = "G2" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<10>" LOC = "J1" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<11>" LOC = "J2" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<12>" LOC = "K1" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<13>" LOC = "K2" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<14>" LOC = "L1" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<15>" LOC = "N12" | IOSTANDARD = LVCMOS33; |
|
NET "o_kp_col<0>" LOC = "P5" | IOSTANDARD = LVCMOS33 | PULLUP; |
NET "o_kp_col<1>" LOC = "N5" | IOSTANDARD = LVCMOS33 | PULLUP; |
NET "o_kp_col<2>" LOC = "N6" | IOSTANDARD = LVCMOS33 | PULLUP; |
NET "o_kp_col<3>" LOC = "P7" | IOSTANDARD = LVCMOS33 | PULLUP; |
|
NET "i_kp_row<0>" LOC = "L14" | IOSTANDARD = LVCMOS33 | PULLUP; |
NET "i_kp_row<1>" LOC = "L13" | IOSTANDARD = LVCMOS33 | PULLUP; |
NET "i_kp_row<2>" LOC = "K14" | IOSTANDARD = LVCMOS33 | PULLUP; |
NET "i_kp_row<3>" LOC = "K13" | IOSTANDARD = LVCMOS33 | PULLUP; |
|
/sw/host/ttybus.h
0,0 → 1,124
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: ttybus.h |
// |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
// Purpose: This is the C++ program on the command side that will interact |
// with a serial port (through DEPP) on an FPGA, to command the |
// WISHBONE on that same FPGA to ... whatever we wish to command it to do. |
// |
// This code does not run on an FPGA, is not a test bench, neither is it |
// a simulator. It is a portion of a command program for commanding an |
// FPGA from an attached host computer. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, 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 TTYBUS_H |
#define TTYBUS_H |
|
#include "llcomms.h" |
#include "devbus.h" |
|
#define RDBUFLN 2048 |
|
class TTYBUS : public DEVBUS { |
public: |
unsigned long m_total_nread; |
private: |
LLCOMMSI *m_dev; |
static const unsigned MAXRDLEN, MAXWRLEN; |
|
bool m_interrupt_flag, m_decode_err, m_addr_set, m_bus_err; |
unsigned int m_lastaddr; |
|
int m_buflen, m_rdfirst, m_rdlast; |
char *m_buf, *m_rdbuf; |
|
bool m_wrloaded; |
int m_rdaddr, m_wraddr; |
BUSW m_readtbl[1024], m_writetbl[512]; |
|
void init(void) { |
m_interrupt_flag = false; |
m_buflen = 0; m_buf = NULL; |
m_addr_set = false; |
bufalloc(64); |
m_bus_err = false; |
m_decode_err = false; |
m_wrloaded = false; |
|
m_rdfirst = m_rdlast = 0; |
m_rdbuf = new char[RDBUFLN]; |
|
m_rdaddr = m_wraddr = 0; |
} |
|
char charenc(const int sixbitval) const; |
unsigned chardec(const char b) const; |
void encode(const int fbits, const BUSW v, char *buf) const; |
unsigned decodestr(const char *buf) const; |
int decodehex(const char hx) const; |
void bufalloc(int len); |
BUSW readword(void); // Reads a word value from the bus |
void readv(const BUSW a, const int inc, const int len, BUSW *buf); |
void writev(const BUSW a, const int p, const int len, const BUSW *buf); |
|
int lclread(char *buf, int len); |
int lclreadcode(char *buf, int len); |
char *encode_address(const BUSW a); |
char *readcmd(const int inc, const int len, char *buf); |
public: |
TTYBUS(LLCOMMSI *comms) : m_dev(comms) { init(); } |
virtual ~TTYBUS(void) { |
m_dev->close(); |
if (m_buf) delete[] m_buf; m_buf = NULL; |
delete m_rdbuf; m_rdbuf = NULL; |
delete m_dev; |
} |
|
void kill(void) { m_dev->close(); } |
void close(void) { m_dev->close(); } |
void writeio(const BUSW a, const BUSW v); |
BUSW readio(const BUSW a); |
void readi(const BUSW a, const int len, BUSW *buf); |
void readz(const BUSW a, const int len, BUSW *buf); |
void writei(const BUSW a, const int len, const BUSW *buf); |
void writez(const BUSW a, const int len, const BUSW *buf); |
bool poll(void) { return m_interrupt_flag; }; |
void usleep(unsigned msec); // Sleep until interrupt |
void wait(void); // Sleep until interrupt |
bool bus_err(void) const { return m_bus_err; }; |
void reset_err(void) { m_bus_err = false; } |
void clear(void) { m_interrupt_flag = false; } |
}; |
|
#endif |
/sw/host/flashdrvr.h
2,16 → 2,16
// |
// Filename: flashdrvr.h |
// |
// Project: XuLA2-LX25 System on a Chip |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
// Purpose: Flash driver. Encapsulate writing to the flash device. |
// |
// Creator: Dan Gisselquist |
// Gisselquist Tecnology, LLC |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2016, Gisselquist Technology, LLC |
// Copyright (C) 2015-2016, 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 |
23,6 → 23,11
// 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 |
// |
/sw/host/deppi.cpp
0,0 → 1,273
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: deppi.cpp |
// |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
// Purpose: Creates a DEPP interface pseudo-character device, similar to |
// what you might get from a serial port or other character device, |
// from the DEPP interface to a CMOD S6 board. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, 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 <stdlib.h> |
#include <unistd.h> |
#include <string.h> |
#include <ctype.h> |
#include <time.h> |
// From Digilent's Adept Library |
#include "dpcdecl.h" |
#include "dmgr.h" |
#include "depp.h" |
|
// From my own library |
#include "llcomms.h" |
#include "deppi.h" |
|
DEPPI::DEPPI(char *szSel) { |
if (!DmgrOpen(&m_dev, szSel)) { |
fprintf(stderr, "Open failed!\n"); |
exit(EXIT_FAILURE); |
} |
|
if (!DeppEnable(m_dev)) { |
fprintf(stderr, "Could not enable DEPP interface\n"); |
exit(EXIT_FAILURE); |
} |
|
m_int = false, m_err = false; |
|
// fprintf(stdout, "Flushing **************\n"); |
flush_read(); |
// fprintf(stdout, "Flushed! **************\n"); |
} |
|
DEPPI::~DEPPI(void) { |
close(); |
} |
|
void DEPPI::close(void) { |
if (m_dev) |
DmgrClose(m_dev); |
m_dev = 0; |
} |
|
void DEPPI::depperr(void) { |
ERC erc = DmgrGetLastError(); |
if(erc != ercNoErc) { |
char scode[cchErcMax], msg[cchErcMsgMax]; |
DmgrSzFromErc(erc, scode, msg); |
fprintf(stderr, "ErrCode : %s\n", scode); |
fprintf(stderr, "ErrMessage: %s\n", msg); |
close(); |
exit(EXIT_FAILURE); |
} |
} |
|
void DEPPI::write(char *buf, int len) { |
bool good = true; |
|
if (false) { |
// Debug code--write one at a time |
fputs("WR: ", stdout); |
for(int i=0; i<len; i++) { |
good = good && DeppPutReg(m_dev, 0, (unsigned char)buf[i], false); |
fputc(buf[i], stdout); |
} fputc('\n', stdout); |
} else |
good = DeppPutRegRepeat(m_dev, 0, (unsigned char *)buf, len, false); |
if (!good) |
depperr(); |
} |
|
int DEPPI::read(char *buf, int len) { |
return read(buf, len, 4); |
} |
|
int DEPPI::read(char *buf, int len, int timeout_ms) { |
int left = len, nr=0; |
struct timespec now, later; |
|
clock_gettime(CLOCK_MONOTONIC, &now); |
|
// printf("USBI::read(%d) (FIFO is %d-%d)\n", len, m_rend, m_rbeg); |
nr = pop_fifo(buf, left); |
left -= nr; |
|
while(left > 0) { |
raw_read(left, timeout_ms); |
nr = pop_fifo(&buf[len-left], left); |
left -= nr; |
|
// printf("\tWHILE (nr = %d, LEFT = %d, len=%d)\n", nr, left, len); |
if (nr == 0) |
break; |
#define TIMEOUT |
#ifdef TIMEOUT |
if (timeout_ms == 0) |
break; |
else if (timeout_ms > 0) { |
clock_gettime(CLOCK_MONOTONIC, &later); |
|
long num_ns = later.tv_nsec - now.tv_nsec, num_ms; |
if (num_ns < 0) { |
num_ns += 1000000000; |
later.tv_sec--; |
} num_ms = num_ns / 1000000; |
if (later.tv_sec > now.tv_sec) |
num_ms += (later.tv_sec - now.tv_sec)*1000; |
|
if (num_ms > timeout_ms) |
break; |
} |
#endif |
} |
|
// printf("READ %d characters (%d req, %d left)\n", len-left, len, left); |
return len-left; |
} |
|
void DEPPI::raw_read(const int clen, int timeout_ms) { |
int empty = RCV_BUFMASK - ((m_rbeg - m_rend)&(RCV_BUFMASK)); |
int len = clen; |
bool good = true; |
|
if (len > empty) |
len = empty; |
if (len > 0) { |
// Fill the tail of our buffer |
int ln = len; |
if (ln > PKTLEN) |
ln = PKTLEN; |
|
// fprintf(stdout, "RAW-READ(%d)\n", ln); |
if (false) { |
// Debug code--read one word at a time |
for(int i=0; i<ln; i++) { |
good = good && DeppGetReg(m_dev, 0, (unsigned char *)&m_rxbuf[i], false); |
usleep(1); |
} |
} else |
good = good && DeppGetRegRepeat(m_dev, 0, (unsigned char *)m_rxbuf, ln, false); |
// fprintf(stdout, "Pushing to FIFO\n"); |
push_fifo(m_rxbuf, ln); |
len -= ln; |
} |
|
if (!good) |
depperr(); |
} |
|
void DEPPI::flush_read(void) { |
while(poll(4)) { |
m_rbeg = m_rend = 0; |
} |
} |
|
void DEPPI::push_fifo(char *buf, int len) { |
char last = 0; |
char *sptr = buf; |
|
// fprintf(stdout, "PUSH(%d)\n", len); |
|
if (m_rbeg != m_rend) |
last = m_rbuf[(m_rbeg-1)&RCV_BUFMASK]; |
for(int i=0; i<len; i++) { |
char v = *sptr++; |
if (((v & 0x80)||((unsigned char)v < 0x10))&&(v == last)) { |
// Skipp any stuff bytes |
// fprintf(stderr, "SKIPPING-1: %02x\n", v & 0x0ff); |
} else if ((unsigned char)v == 0x0ff) { |
// Skipp any not-yet-ready bytes |
// fprintf(stdout, "SKIPPING-2: %02x\n", 0x0ff); |
} else { |
m_rbuf[m_rbeg] = v; |
// fprintf(stdout, "PUSHING: %02x %c\n", v&0x0ff, |
// isprint(v)?v:'.'); |
m_rbeg = (m_rbeg+1)&(RCV_BUFMASK); |
} last = v; |
} |
} |
|
int DEPPI::pop_fifo(char *buf, int len) { |
int avail = (m_rbeg - m_rend)&(RCV_BUFMASK); |
int left = len; |
int nr = 0; |
|
// printf("Attempting to pop %d items from FIFO (%d - %d)\n", |
// len, m_rend, m_rbeg); |
while((avail > 0)&&(left > 0)) { |
int ln = RCV_BUFLEN-m_rend; |
if (ln > left) |
ln = left; |
if (ln > avail) |
ln = avail; |
memcpy(&buf[len-left], &m_rbuf[m_rend], ln); |
left -= ln; |
avail -= ln; |
m_rend = (m_rend + ln)&(RCV_BUFMASK); |
nr += ln; |
|
} |
|
return nr; |
} |
|
bool DEPPI::poll(unsigned ms) { |
int avail = (m_rbeg-m_rend)&(RCV_BUFMASK); |
bool r = true; |
|
// printf("POLL\n"); |
if ((avail < 2)&&((avail<1)||(m_rbuf[m_rend]&0x80)||(m_rbuf[m_rend]<0x10))) { |
// printf("POLL -- CALLS RAW READ\n"); |
raw_read(4,ms); |
avail = (m_rbeg-m_rend)&(RCV_BUFMASK); |
|
if (avail != 0) { |
// Read 'til there's nothing more to be read |
char v = (m_rbuf[(m_rbeg-1)&(RCV_BUFMASK)]); |
while(((v&0x80)==0)&&((unsigned)v>=0x10)&&(avail < RCV_BUFMASK-32)) { |
raw_read(26,ms); |
if (avail == ((m_rbeg-m_rend)&(RCV_BUFMASK))) |
break; // We didn't read anything more |
avail = (m_rbeg-m_rend)&(RCV_BUFMASK); |
// printf("POLL/LOOP -- %d available\n", avail); |
} |
if (avail < 1) |
r = false; |
else if ((avail==1)&&((m_rbuf[m_rend]&0x80)||(m_rbuf[m_rend]<0x10))) |
r = false; |
} else r = false; |
} |
// printf("POLL -- is %s\n", (r)?"true":"false"); |
|
return r; |
} |
/sw/host/zipload.cpp
0,0 → 1,516
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: zipload.cpp |
// |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
// Purpose: To load the flash--both a the two configurations and the |
// a program for the ZipCPU into (flash) memory. |
// |
// Steps: |
// 1. Reboot the CMod into the alternate/debug/command mode |
// 2. Load flash memory |
// 3. Reload (reboot) the CMod configuration into ZipCPU mode |
// 4. Program should start on its own. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, 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 |
// |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// |
// |
#include <stdio.h> |
#include <stdlib.h> |
#include <sys/types.h> |
#include <sys/stat.h> |
#include <fcntl.h> |
#include <unistd.h> |
#include <strings.h> |
#include <ctype.h> |
#include <string.h> |
#include <signal.h> |
#include <assert.h> |
|
#include "devbus.h" |
#include "llcomms.h" |
#include "deppi.h" |
#include "regdefs.h" |
#include "flashdrvr.h" |
|
bool iself(const char *fname) { |
FILE *fp; |
bool ret = true; |
|
if ((!fname)||(!fname[0])) |
return false; |
|
fp = fopen(fname, "rb"); |
|
if (!fp) return false; |
if (0x7f != fgetc(fp)) ret = false; |
if ('E' != fgetc(fp)) ret = false; |
if ('L' != fgetc(fp)) ret = false; |
if ('F' != fgetc(fp)) ret = false; |
fclose(fp); |
return ret; |
} |
|
long fgetwords(FILE *fp) { |
// Return the number of words in the current file, and return the |
// file as though it had never been adjusted |
long fpos, flen; |
fpos = ftell(fp); |
if (0 != fseek(fp, 0l, SEEK_END)) { |
fprintf(stderr, "ERR: Could not determine file size\n"); |
perror("O/S Err:"); |
exit(-2); |
} flen = ftell(fp); |
if (0 != fseek(fp, fpos, SEEK_SET)) { |
fprintf(stderr, "ERR: Could not seek on file\n"); |
perror("O/S Err:"); |
exit(-2); |
} flen /= sizeof(FPGA::BUSW); |
return flen; |
} |
|
FPGA *m_fpga; |
class SECTION { |
public: |
unsigned m_start, m_len; |
FPGA::BUSW m_data[1]; |
}; |
|
SECTION **singlesection(int nwords) { |
fprintf(stderr, "NWORDS = %d\n", nwords); |
size_t sz = (2*(sizeof(SECTION)+sizeof(SECTION *)) |
+(nwords-1)*(sizeof(FPGA::BUSW))); |
char *d = (char *)malloc(sz); |
SECTION **r = (SECTION **)d; |
memset(r, 0, sz); |
r[0] = (SECTION *)(&d[2*sizeof(SECTION *)]); |
r[0]->m_len = nwords; |
r[1] = (SECTION *)(&r[0]->m_data[r[0]->m_len]); |
r[0]->m_start = 0; |
r[1]->m_start = 0; |
r[1]->m_len = 0; |
|
return r; |
} |
|
SECTION **rawsection(const char *fname) { |
SECTION **secpp, *secp; |
unsigned num_words; |
FILE *fp; |
int nr; |
|
fp = fopen(fname, "r"); |
if (fp == NULL) { |
fprintf(stderr, "Could not open: %s\n", fname); |
exit(-1); |
} |
|
if ((num_words=fgetwords(fp)) > FLASHWORDS-(RESET_ADDRESS-SPIFLASH)) { |
fprintf(stderr, "File overruns flash memory\n"); |
exit(-1); |
} |
secpp = singlesection(num_words); |
secp = secpp[0]; |
secp->m_start = RAMBASE; |
secp->m_len = num_words; |
nr= fread(secp->m_data, sizeof(FPGA::BUSW), num_words, fp); |
if (nr != (int)num_words) { |
fprintf(stderr, "Could not read entire file\n"); |
perror("O/S Err:"); |
exit(-2); |
} assert(secpp[1]->m_len == 0); |
|
return secpp; |
} |
|
unsigned byteswap(unsigned n) { |
unsigned r; |
|
r = (n&0x0ff); n>>= 8; |
r = (r<<8) | (n&0x0ff); n>>= 8; |
r = (r<<8) | (n&0x0ff); n>>= 8; |
r = (r<<8) | (n&0x0ff); n>>= 8; |
|
return r; |
} |
|
// #define CHEAP_AND_EASY |
#ifdef CHEAP_AND_EASY |
#else |
#include <libelf.h> |
#include <gelf.h> |
|
void elfread(const char *fname, unsigned &entry, SECTION **§ions) { |
Elf *e; |
int fd, i; |
size_t n; |
char *id; |
Elf_Kind ek; |
GElf_Ehdr ehdr; |
GElf_Phdr phdr; |
const bool dbg = false; |
|
if (elf_version(EV_CURRENT) == EV_NONE) { |
fprintf(stderr, "ELF library initialization err, %s\n", elf_errmsg(-1)); |
perror("O/S Err:"); |
exit(EXIT_FAILURE); |
} if ((fd = open(fname, O_RDONLY, 0)) < 0) { |
fprintf(stderr, "Could not open %s\n", fname); |
perror("O/S Err:"); |
exit(EXIT_FAILURE); |
} if ((e = elf_begin(fd, ELF_C_READ, NULL))==NULL) { |
fprintf(stderr, "Could not run elf_begin, %s\n", elf_errmsg(-1)); |
exit(EXIT_FAILURE); |
} |
|
ek = elf_kind(e); |
if (ek == ELF_K_ELF) { |
; // This is the kind of file we should expect |
} else if (ek == ELF_K_AR) { |
fprintf(stderr, "Cannot run an archive!\n"); |
exit(EXIT_FAILURE); |
} else if (ek == ELF_K_NONE) { |
; |
} else { |
fprintf(stderr, "Unexpected ELF file kind!\n"); |
exit(EXIT_FAILURE); |
} |
|
if (gelf_getehdr(e, &ehdr) == NULL) { |
fprintf(stderr, "getehdr() failed: %s\n", elf_errmsg(-1)); |
exit(EXIT_FAILURE); |
} if ((i=gelf_getclass(e)) == ELFCLASSNONE) { |
fprintf(stderr, "getclass() failed: %s\n", elf_errmsg(-1)); |
exit(EXIT_FAILURE); |
} if ((id = elf_getident(e, NULL)) == NULL) { |
fprintf(stderr, "getident() failed: %s\n", elf_errmsg(-1)); |
exit(EXIT_FAILURE); |
} if (i != ELFCLASS32) { |
fprintf(stderr, "This is a 64-bit ELF file, ZipCPU ELF files are all 32-bit\n"); |
exit(EXIT_FAILURE); |
} |
|
if (dbg) { |
printf(" %-20s 0x%jx\n", "e_type", (uintmax_t)ehdr.e_type); |
printf(" %-20s 0x%jx\n", "e_machine", (uintmax_t)ehdr.e_machine); |
printf(" %-20s 0x%jx\n", "e_version", (uintmax_t)ehdr.e_version); |
printf(" %-20s 0x%jx\n", "e_entry", (uintmax_t)ehdr.e_entry); |
printf(" %-20s 0x%jx\n", "e_phoff", (uintmax_t)ehdr.e_phoff); |
printf(" %-20s 0x%jx\n", "e_shoff", (uintmax_t)ehdr.e_shoff); |
printf(" %-20s 0x%jx\n", "e_flags", (uintmax_t)ehdr.e_flags); |
printf(" %-20s 0x%jx\n", "e_ehsize", (uintmax_t)ehdr.e_ehsize); |
printf(" %-20s 0x%jx\n", "e_phentsize", (uintmax_t)ehdr.e_phentsize); |
printf(" %-20s 0x%jx\n", "e_shentsize", (uintmax_t)ehdr.e_shentsize); |
printf("\n"); |
} |
|
|
// Check whether or not this is an ELF file for the ZipCPU ... |
if (ehdr.e_machine != 0x0dadd) { |
fprintf(stderr, "This is not a ZipCPU ELF file\n"); |
exit(EXIT_FAILURE); |
} |
|
// Get our entry address |
entry = ehdr.e_entry; |
|
|
// Now, let's go look at the program header |
if (elf_getphdrnum(e, &n) != 0) { |
fprintf(stderr, "elf_getphdrnum() failed: %s\n", elf_errmsg(-1)); |
exit(EXIT_FAILURE); |
} |
|
unsigned total_octets = 0, current_offset=0, current_section=0; |
for(i=0; i<(int)n; i++) { |
total_octets += sizeof(SECTION *)+sizeof(SECTION); |
|
if (gelf_getphdr(e, i, &phdr) != &phdr) { |
fprintf(stderr, "getphdr() failed: %s\n", elf_errmsg(-1)); |
exit(EXIT_FAILURE); |
} |
|
if (dbg) { |
printf(" %-20s 0x%x\n", "p_type", phdr.p_type); |
printf(" %-20s 0x%jx\n", "p_offset", phdr.p_offset); |
printf(" %-20s 0x%jx\n", "p_vaddr", phdr.p_vaddr); |
printf(" %-20s 0x%jx\n", "p_paddr", phdr.p_paddr); |
printf(" %-20s 0x%jx\n", "p_filesz", phdr.p_filesz); |
printf(" %-20s 0x%jx\n", "p_memsz", phdr.p_memsz); |
printf(" %-20s 0x%x [", "p_flags", phdr.p_flags); |
|
if (phdr.p_flags & PF_X) printf(" Execute"); |
if (phdr.p_flags & PF_R) printf(" Read"); |
if (phdr.p_flags & PF_W) printf(" Write"); |
printf("]\n"); |
printf(" %-20s 0x%jx\n", "p_align", phdr.p_align); |
} |
|
total_octets += phdr.p_memsz; |
} |
|
char *d = (char *)malloc(total_octets + sizeof(SECTION)+sizeof(SECTION *)); |
memset(d, 0, total_octets); |
|
SECTION **r = sections = (SECTION **)d; |
current_offset = (n+1)*sizeof(SECTION *); |
current_section = 0; |
|
for(i=0; i<(int)n; i++) { |
r[i] = (SECTION *)(&d[current_offset]); |
|
if (gelf_getphdr(e, i, &phdr) != &phdr) { |
fprintf(stderr, "getphdr() failed: %s\n", elf_errmsg(-1)); |
exit(EXIT_FAILURE); |
} |
|
if (dbg) { |
printf(" %-20s 0x%jx\n", "p_offset", phdr.p_offset); |
printf(" %-20s 0x%jx\n", "p_vaddr", phdr.p_vaddr); |
printf(" %-20s 0x%jx\n", "p_paddr", phdr.p_paddr); |
printf(" %-20s 0x%jx\n", "p_filesz", phdr.p_filesz); |
printf(" %-20s 0x%jx\n", "p_memsz", phdr.p_memsz); |
printf(" %-20s 0x%x [", "p_flags", phdr.p_flags); |
|
if (phdr.p_flags & PF_X) printf(" Execute"); |
if (phdr.p_flags & PF_R) printf(" Read"); |
if (phdr.p_flags & PF_W) printf(" Write"); |
printf("]\n"); |
|
printf(" %-20s 0x%jx\n", "p_align", phdr.p_align); |
} |
|
current_section++; |
|
r[i]->m_start = phdr.p_vaddr; |
r[i]->m_len = phdr.p_filesz/ sizeof(FPGA::BUSW); |
|
current_offset += phdr.p_memsz + sizeof(SECTION); |
|
// Now, let's read in our section ... |
if (lseek(fd, phdr.p_offset, SEEK_SET) < 0) { |
fprintf(stderr, "Could not seek to file position %08lx\n", phdr.p_offset); |
perror("O/S Err:"); |
exit(EXIT_FAILURE); |
} if (phdr.p_filesz > phdr.p_memsz) |
phdr.p_filesz = 0; |
if (read(fd, r[i]->m_data, phdr.p_filesz) != (int)phdr.p_filesz) { |
fprintf(stderr, "Didnt read entire section\n"); |
perror("O/S Err:"); |
exit(EXIT_FAILURE); |
} |
|
// Next, we need to byte swap it from big to little endian |
for(unsigned j=0; j<r[i]->m_len; j++) |
r[i]->m_data[j] = byteswap(r[i]->m_data[j]); |
|
if (dbg) for(unsigned j=0; j<r[i]->m_len; j++) |
fprintf(stderr, "ADR[%04x] = %08x\n", r[i]->m_start+j, |
r[i]->m_data[j]); |
} |
|
r[i] = (SECTION *)(&d[current_offset]); |
r[current_section]->m_start = 0; |
r[current_section]->m_len = 0; |
|
elf_end(e); |
close(fd); |
} |
#endif |
|
void usage(void) { |
printf("USAGE: ziprun [-h] [<bit-file> [<alt-bit-file>]] <zip-program-file>\n"); |
printf("\n" |
"\t-h\tDisplay this usage statement\n"); |
} |
|
int main(int argc, char **argv) { |
int skp=0; |
bool permit_raw_files = false; |
unsigned entry = RAMBASE; |
FLASHDRVR *flash = NULL; |
const char *bitfile = NULL, *altbitfile = NULL; |
|
if (argc < 2) { |
usage(); |
exit(EXIT_SUCCESS); |
} |
|
skp=1; |
for(int argn=0; argn<argc-skp; argn++) { |
if (argv[argn+skp][0] == '-') { |
switch(argv[argn+skp][1]) { |
case 'h': |
usage(); |
exit(EXIT_SUCCESS); |
case 'r': |
permit_raw_files = true; |
break; |
} skp++; argn--; |
} else { // Check for bit files |
int sl = strlen(argv[argn+skp]); |
if ((sl>4)&&(strcmp(&argv[argn+skp][sl-4],".bit")==0)) { |
if (bitfile == NULL) |
bitfile = argv[argn+skp]; |
else if (altbitfile == NULL) |
altbitfile = argv[argn+skp]; |
else { |
fprintf(stderr, "Err: Too many bit files listed\n"); |
exit(EXIT_FAILURE); |
} skp++; argn--; |
} else |
argv[argn] = argv[argn+skp]; |
} |
} argc -= skp; |
|
|
if ((bitfile)&&(access(bitfile,R_OK)!=0)) { |
fprintf(stderr, "Cannot open bitfile, %s\n", bitfile); |
exit(EXIT_FAILURE); |
} if ((altbitfile)&&(access(altbitfile,R_OK)!=0)) { |
fprintf(stderr, "Cannot open alternate bitfile, %s\n", |
altbitfile); |
exit(EXIT_FAILURE); |
} if(((!bitfile)&&(argc<=0)) || ((argc>0)&&(access(argv[0],R_OK)!=0))) { |
// If there's no code file, or the code file cannot be opened |
if (argc>0) |
fprintf(stderr, "Cannot open executable, %s\n", argv[0]); |
else |
usage(); |
exit(EXIT_FAILURE); |
} |
|
const char *codef = (argc>0)?argv[0]:NULL; |
DEVBUS::BUSW *fbuf = new DEVBUS::BUSW[FLASHWORDS]; |
|
// Set the flash buffer to all ones |
memset(fbuf, -1, FLASHWORDS*sizeof(fbuf[0])); |
|
{ |
char szSel[64]; |
strcpy(szSel, "SN:210282768825"); |
m_fpga = new FPGA(new DEPPI(szSel)); |
} |
|
flash = new FLASHDRVR(m_fpga); |
|
// First, see if we need to load a bit file |
if (bitfile) { |
int len; |
FILE *fp = fopen(bitfile, "rb"); |
|
fseek(fp, 0x5dl, SEEK_SET); |
len = fread(&fbuf[CONFIG_ADDRESS-SPIFLASH], |
sizeof(fbuf[0]), |
FLASHWORDS-(CONFIG_ADDRESS-SPIFLASH), fp); |
assert(len + CONFIG_ADDRESS < ALTCONFIG_ADDRESS); |
fclose(fp); |
|
for(int i=0; i<4; i++) { |
// printf("0x%08x\n", fbuf[i]); |
assert(fbuf[i] == 0x0ffffffff); |
} // printf("0x%08x\n", fbuf[4]); |
assert(fbuf[4] == 0x0665599aa); |
|
printf("Loading: %s\n", bitfile); |
if (!flash->write(CONFIG_ADDRESS, len, &fbuf[CONFIG_ADDRESS-SPIFLASH], true)) { |
fprintf(stderr, "Could not write primary bitfile\n"); |
exit(EXIT_FAILURE); |
} |
} if (altbitfile) { |
int len; |
FILE *fp = fopen(altbitfile, "rb"); |
|
// The alternate configuration follows the first configuration |
len = fread(&fbuf[ALTCONFIG_ADDRESS-SPIFLASH], |
sizeof(fbuf[0]), |
FLASHWORDS-(ALTCONFIG_ADDRESS-SPIFLASH), fp); |
assert(len + ALTCONFIG_ADDRESS < RESET_ADDRESS); |
fclose(fp); |
printf("Loading: %s\n", altbitfile); |
|
if (!flash->write(ALTCONFIG_ADDRESS, len, &fbuf[ALTCONFIG_ADDRESS-SPIFLASH], true)) { |
fprintf(stderr, "Could not write alternate bitfile\n"); |
exit(EXIT_FAILURE); |
} |
} |
|
if (codef) try { |
SECTION **secpp = NULL, *secp; |
|
if(iself(codef)) { |
// zip-readelf will help with both of these ... |
elfread(codef, entry, secpp); |
assert(entry == RESET_ADDRESS); |
} else if (permit_raw_files) { |
secpp = rawsection(codef); |
entry = RESET_ADDRESS; |
} else { |
fprintf(stderr, "ERR: %s is not in ELF format\n", codef); |
exit(EXIT_FAILURE); |
} |
|
printf("Loading: %s\n", codef); |
// assert(secpp[1]->m_len = 0); |
for(int i=0; secpp[i]->m_len; i++) { |
bool valid = false; |
secp= secpp[i]; |
if ((secp->m_start >= RESET_ADDRESS) |
&&(secp->m_start+secp->m_len |
<= SPIFLASH+FLASHWORDS)) |
valid = true; |
if (!valid) { |
fprintf(stderr, "No such memory on board: 0x%08x - %08x\n", |
secp->m_start, secp->m_start+secp->m_len); |
exit(EXIT_FAILURE); |
} |
} |
|
for(int i=0; secpp[i]->m_len; i++) { |
secp = secpp[i]; |
if (!flash->write(secp->m_start, secp->m_len, secp->m_data, true)) { |
fprintf(stderr, "ERR: Could not write program to flash\n"); |
exit(EXIT_FAILURE); |
} |
} |
m_fpga->readio(R_VERSION); // Check for bus errors |
|
// Now ... how shall we start this CPU? |
printf("The CPU should be fully loaded, you may now start\n"); |
printf("it. To start the CPU, either toggle power or type\n"); |
printf("%% wbregs fpgagen1 0 \n"); |
printf("%% wbregs fpgagen2 0x0300 \n"); |
printf("%% wbregs fpgacmd 14 \n"); |
} catch(BUSERR a) { |
fprintf(stderr, "XULA-BUS error: %08x\n", a.addr); |
exit(-2); |
} |
|
delete m_fpga; |
|
return EXIT_SUCCESS; |
} |
|
/sw/host/deppi.h
0,0 → 1,83
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: deppi.h |
// |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
// Purpose: This package attempts to convet a DEPP over USB based |
// communication system into something similar to a serial port |
// based communication system. Some differences include the fact that, |
// if the DEPP port isn't polled, nothing comes out of the port. Hence, |
// on connecting (or polling for the first time) ... there might be a |
// bunch of stuff to (initially) ignore. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, 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 DEPPI_H |
#define DEPPI_H |
|
#include "dpcdecl.h" |
#include "dmgr.h" |
// #include "devbus.h" |
|
// |
#define PKTLEN 32 |
#define RCV_BUFLEN 512 |
#define RCV_BUFMASK (RCV_BUFLEN-1) |
|
#include "llcomms.h" |
|
class DEPPI : public LLCOMMSI { // DEPP Interface |
private: |
HIF m_dev; |
bool m_int, m_err; |
char m_rbuf[RCV_BUFLEN]; |
char m_txbuf[2*PKTLEN], m_rxbuf[2*PKTLEN]; |
int m_rbeg, m_rend; |
|
virtual int pop_fifo(char *buf, int len); |
virtual void push_fifo(char *buf, int len); |
virtual void raw_read(int len, int timeout_ms); |
virtual void flush_read(void); |
void depperr(void); |
|
public: |
DEPPI(char *szSel); |
~DEPPI(void); |
|
virtual void close(void); |
virtual int read(char *buf, int len); |
virtual int read(char *buf, int len, int timeout_ms); |
virtual void write(char *buf, int len); |
virtual bool poll(unsigned ms); |
}; |
|
#endif // DEPPI_H |
|
/sw/host/llcomms.cpp
0,0 → 1,150
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: llcomms.cpp |
// |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
// Purpose: This defines a C++ interface on the command side that can |
// interact with an FPGA, both sending and receiving characters. |
// Any bus interaction will call routines from this lower level |
// library to accomplish the actual connection to and |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, 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 <sys/socket.h> |
#include <sys/types.h> |
#include <sys/stat.h> |
#include <fcntl.h> |
#include <termios.h> |
#include <netinet/in.h> |
#include <netdb.h> |
#include <stdio.h> |
#include <string.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include <errno.h> |
#include <arpa/inet.h> |
#include <assert.h> |
#include <strings.h> |
#include <poll.h> |
#include <ctype.h> |
|
#include "llcomms.h" |
|
LLCOMMSI::LLCOMMSI(void) { |
m_fdw = -1; |
m_fdr = -1; |
m_total_nread = 0l; |
m_total_nwrit = 0l; |
} |
|
void LLCOMMSI::write(char *buf, int len) { |
int nw; |
nw = ::write(m_fdw, buf, len); |
m_total_nwrit += nw; |
assert(nw == len); |
} |
|
int LLCOMMSI::read(char *buf, int len) { |
int nr; |
nr = ::read(m_fdr, buf, len); |
m_total_nread += nr; |
return nr; |
} |
|
void LLCOMMSI::close(void) { |
if(m_fdw>=0) ::close(m_fdw); |
if((m_fdr>=0)&&(m_fdr != m_fdw)) ::close(m_fdr); |
m_fdw = m_fdr = -1; |
} |
|
bool LLCOMMSI::poll(unsigned ms) { |
struct pollfd fds; |
|
fds.fd = m_fdr; |
fds.events = POLLIN; |
::poll(&fds, 1, ms); |
|
if (fds.revents & POLLIN) { |
return true; |
} else return false; |
} |
|
TTYCOMMS::TTYCOMMS(const char *dev) { |
m_fdr = ::open(dev, O_RDWR | O_NONBLOCK); |
if (m_fdr < 0) { |
printf("\n Error : Could not open %s\n", dev); |
perror("O/S Err:"); |
exit(-1); |
} |
|
if (isatty(m_fdr)) { |
struct termios tb; |
tcgetattr(m_fdr, &tb); |
cfmakeraw(&tb); |
// tb.c_iflag &= (~(IXON|IXOFF)); |
tb.c_cflag &= (~(CRTSCTS)); |
tcsetattr(m_fdr, TCSANOW, &tb); |
tcflow(m_fdr, TCOON); |
} |
|
m_fdw = m_fdr; |
} |
|
NETCOMMS::NETCOMMS(const char *host, const int port) { |
struct sockaddr_in serv_addr; |
struct hostent *hp; |
|
if ((m_fdr = socket(AF_INET, SOCK_STREAM, 0)) < 0) { |
printf("\n Error : Could not create socket \n"); |
exit(-1); |
} |
|
memset(&serv_addr, '0', sizeof(serv_addr)); |
|
hp = gethostbyname(host); |
if (hp == NULL) { |
printf("Could not get host entity for %s\n", host); |
perror("O/S Err:"); |
exit(-1); |
} |
bcopy(hp->h_addr, &serv_addr.sin_addr.s_addr, hp->h_length); |
|
serv_addr.sin_family = AF_INET; |
serv_addr.sin_port = htons(port); |
|
if (connect(m_fdr,(struct sockaddr *)&serv_addr, sizeof(serv_addr))< 0){ |
perror("Connect Failed Err"); |
exit(-1); |
} |
|
m_fdw = m_fdr; |
} |
|
/sw/host/llcomms.h
0,0 → 1,70
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: llcomms.h |
// |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
// Purpose: This defines a C++ interface on the command side that can |
// interact with an FPGA, both sending and receiving characters. |
// Any bus interaction will call routines from this lower level |
// library to accomplish the actual connection to and |
// transmission to/from the board. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, 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 LLCOMMS_H |
#define LLCOMMS_H |
|
class LLCOMMSI { |
protected: |
int m_fdw, m_fdr; |
LLCOMMSI(void); |
public: |
unsigned long m_total_nread, m_total_nwrit; |
|
virtual ~LLCOMMSI(void) { close(); } |
virtual void kill(void) { this->close(); }; |
virtual void close(void); |
virtual void write(char *buf, int len); |
virtual int read(char *buf, int len); |
virtual bool poll(unsigned ms); |
}; |
|
class TTYCOMMS : public LLCOMMSI { |
public: |
TTYCOMMS(const char *dev); |
}; |
|
class NETCOMMS : public LLCOMMSI { |
public: |
NETCOMMS(const char *dev, const int port); |
}; |
|
#endif |
/sw/host/regdefs.h
102,34 → 102,35
// RAM memory space |
#define RAMBASE 0x00002000 |
#define MEMWORDS (1<<12) |
#define RAMLEN MEMWORDS |
|
// Flash memory space |
#define SPIFLASH 0x00040000 |
#define FLASHWORDS (1<<18) |
// SDRAM memory space |
#define SDRAMBASE 0x00400000 |
#define SDRAMWORDS (1<<24) |
#define SPIFLASH 0x00400000 |
#define FLASHWORDS (1<<22) |
#define CONFIG_ADDRESS 0x00400000 // Main Xilinx configuration (ZipCPU) |
#define ALTCONFIG_ADDRESS 0x440000 // Alternate Xilinx configuration (Debug) |
#define RESET_ADDRESS 0x00480000 // ZipCPU Reset address |
|
// Interrupt control constants |
// #define GIE 0x80000000 // Enable all interrupts |
// #define SCOPEN 0x80080008 // Enable WBSCOPE interrupts |
// #define ISPIF_EN 0x80040004 // Enable SPI Flash interrupts |
// #define ISPIF_DIS 0x00040000 // Disable SPI Flash interrupts |
// #define ISPIF_CLR 0x00000004 // Clear pending SPI Flash interrupt |
#define GIE 0x80000000 // Enable all interrupts |
#define SCOPEN 0x80040004 // Enable WBSCOPE interrupts |
#define ISPIF_EN 0x90001000 // Enable SPI Flash interrupts |
#define ISPIF_DIS 0x10000000 // Disable SPI Flash interrupts |
#define ISPIF_CLR 0x10001000 // Clear pending SPI Flash interrupt |
|
// Flash control constants |
#define ERASEFLAG 0x80000000 |
#define DISABLEWP 0x10000000 |
|
#define SZPAGE 64 |
#define PGLEN 64 |
#define NPAGES 32 |
// Sectors are defined as 64 kB (16 kW) |
#define SZPAGE 64 // 256 bytes |
#define PGLEN 64 // 256 bytes |
#define NPAGES 256 // 64 kB sectors / 256 bytes is ... |
#define SECTORSZ (NPAGES * SZPAGE) |
#define NSECTORS 256 |
#define SECTOROF(A) ((A) & (-1<<10)) |
#define NSECTORS (FLASHWORDS/SECTORSZ) // 256 sectors |
#define SECTOROF(A) ((A) & (-1<<14)) // 64 kB ea |
#define PAGEOF(A) ((A) & (-1<<6)) |
|
#define RAMLEN MEMWORDS |
|
// Scop definition/sequences |
#define SCOPE_NO_RESET 0x80000000 |
#define SCOPE_TRIGGER (0x08000000|SCOPE_NO_RESET) |
152,5 → 153,7
// #include "deppbus.h" |
|
// typedef DEPPBUS FPGA; |
#include "ttybus.h" |
typedef TTYBUS FPGA; |
|
#endif |
/sw/host/wbregs.cpp
48,11 → 48,25
#include <signal.h> |
#include <assert.h> |
|
#include "deppbus.h" |
#include "devbus.h" |
|
#ifdef SIMPLE_DEPPBUS |
# include "deppbus.h" |
#else |
# include "llcomms.h" |
# include "deppi.h" |
# include "ttybus.h" |
|
#endif |
|
// #include "port.h" |
#include "regdefs.h" |
|
typedef DEPPBUS FPGA; |
#ifdef SIMPLE_DEPPBUS |
# define FPGAOPEN(SN) new DEPPBUS(SN); |
#else |
# define FPGAOPEN(SN) new FPGA(new DEPPI(SN)) |
#endif |
|
FPGA *m_fpga; |
void closeup(int v) { |
75,10 → 89,6
argv[argn] = argv[argn+skp]; |
} argc -= skp; |
|
char szSel[64]; |
strcpy(szSel, "SN:210282768825"); |
m_fpga = new DEPPBUS(szSel); |
|
signal(SIGSTOP, closeup); |
signal(SIGHUP, closeup); |
|
94,6 → 104,10
if (nm == NULL) |
nm = "no name"; |
|
char szSel[64]; |
strcpy(szSel, "SN:210282768825"); |
m_fpga = FPGAOPEN(szSel); |
|
if (argc < 2) { |
FPGA::BUSW v; |
try { |
/sw/host/readflash.cpp
0,0 → 1,126
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: readflash.cpp |
// |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
// Purpose: Read/Empty the entire contents of the flash memory to a file. |
// The flash is unchanged by this process. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, 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 <stdlib.h> |
#include <unistd.h> |
#include <strings.h> |
#include <ctype.h> |
#include <string.h> |
#include <signal.h> |
#include <assert.h> |
|
#include "devbus.h" |
#include "llcomms.h" |
#include "deppi.h" |
#include "ttybus.h" |
#include "regdefs.h" |
|
#define FPGAOPEN(SN) new FPGA(new DEPPI(SN)) |
|
FPGA *m_fpga; |
void closeup(int v) { |
m_fpga->kill(); |
exit(0); |
} |
|
// #define DUMPMEM RAMBASE |
// #define DUMPWORDS MEMWORDS |
|
#define DUMPMEM SPIFLASH |
#define DUMPWORDS FLASHWORDS // 1MB Flash |
|
int main(int argc, char **argv) { |
FILE *fp; |
const int BUFLN = DUMPWORDS; |
FPGA::BUSW *buf = new FPGA::BUSW[BUFLN]; |
|
char szSel[64]; |
strcpy(szSel, "SN:210282768825"); |
m_fpga = FPGAOPEN(szSel); |
|
fprintf(stderr, "Before starting, nread = %ld\n", |
m_fpga->m_total_nread); |
|
// Start with testing the version: |
printf("VERSION: %08x\n", m_fpga->readio(R_VERSION)); |
|
// SPI flash testing |
// Enable the faster (vector) reads |
bool vector_read = true; |
unsigned sz; |
|
if (vector_read) { |
try { |
for(int i=0; i<BUFLN; i+= 2048) { |
printf("i = %02x / %04x, addr = i + %04x = %08x\n", i, BUFLN, DUMPMEM, i+DUMPMEM); |
|
m_fpga->readi(DUMPMEM+i, 2048, &buf[i]); |
}} catch(BUSERR a) { |
printf("%08x : BUS-ERR\n", a.addr); |
} |
} else { |
for(int i=0; i<BUFLN; i++) { |
buf[i] = m_fpga->readio(DUMPMEM+i); |
// if (0 == (i&0x0ff)) |
printf("i = %02x / %04x, addr = i + %04x = %08x\n", i, BUFLN, DUMPMEM, i+DUMPMEM); |
} |
} |
printf("\nREAD-COMPLETE\n"); |
|
// Now, let's find the end |
sz = BUFLN-1; |
while((sz>0)&&(buf[sz] == 0xffffffff)) |
sz--; |
sz+=1; |
printf("The size of the buffer is 0x%06x or %d words\n", sz, sz); |
|
fp = fopen("qspiflash.bin","w"); |
fwrite(buf, sizeof(buf[0]), sz, fp); |
fclose(fp); |
|
printf("The read was accomplished in %ld bytes over the UART\n", |
m_fpga->m_total_nread); |
|
if (m_fpga->poll()) |
printf("FPGA was interrupted\n"); |
delete m_fpga; |
} |
|
|
/sw/host/ttybus.cpp
0,0 → 1,631
//////////////////////////////////////////////////////////////////////////////// |
// |
// Filename: ttybus.cpp |
// |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
// Purpose: This is the C++ program on the command side that will interact |
// with a serial port (through DEPP) on an FPGA, to command the |
// WISHBONE on that same FPGA to ... whatever we wish to command it to do. |
// |
// This code does not run on an FPGA, is not a test bench, neither is it |
// a simulator. It is a portion of a command program for commanding an |
// FPGA from an attached host computer. |
// |
// Creator: Dan Gisselquist, Ph.D. |
// Gisselquist Technology, LLC |
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015-2016, 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 <sys/socket.h> |
#include <sys/types.h> |
#include <sys/stat.h> |
#include <fcntl.h> |
#include <termios.h> |
#include <netinet/in.h> |
#include <netdb.h> |
#include <stdio.h> |
#include <string.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include <errno.h> |
#include <arpa/inet.h> |
#include <assert.h> |
#include <strings.h> |
#include <poll.h> |
#include <ctype.h> |
|
#include "ttybus.h" |
|
#define TTYC_IDLE '0' |
#define TTYC_BUSY '1' |
#define TTYC_WRITE '2' |
#define TTYC_RESET '3' |
#define TTYC_INT '4' |
#define TTYC_ERR '5' |
|
const unsigned TTYBUS::MAXRDLEN = 1024; |
const unsigned TTYBUS::MAXWRLEN = 32; |
|
#define DBGPRINTF null |
// #define DBGPRINTF printf |
// #define DBGPRINTF filedump |
|
void null(...) {} |
#include <stdarg.h> |
// #include <varargs.h> |
/* |
void filedump(const char *fmt, ...) { |
static FILE *dbgfp = NULL; |
va_list args; |
|
if (!dbgfp) |
dbgfp = fopen("debug.txt", "w"); |
va_start(args, fmt); |
vfprintf(dbgfp, fmt, args); |
va_end(args); |
fflush(dbgfp); |
} |
*/ |
|
char TTYBUS::charenc(const int sixbitval) const { |
if (sixbitval < 10) |
return '0' + sixbitval; |
else if (sixbitval < 10+26) |
return 'A' - 10 + sixbitval; |
else if (sixbitval < 10+26+26) |
return 'a' - 10 - 26 + sixbitval; |
else if (sixbitval == 0x3e) |
return '@'; |
else if (sixbitval == 0x3f) |
return '%'; |
|
fprintf(stderr, "INTERNAL ERR: SIXBITVAL isn\'t!!!! sixbitval = %08x\n", sixbitval); |
assert((sixbitval & (~0x03f))==0); |
return 0; |
} |
|
unsigned TTYBUS::chardec(const char b) const { |
if ((b >= '0')&&(b <= '9')) |
return b-'0'; |
else if ((b >= 'A')&&(b <= 'Z')) |
return b-'A'+10; |
else if ((b >= 'a')&&(b <= 'z')) |
return b-'a'+36; |
else if (b == '@') |
return 0x03e; |
else if (b == '%') |
return 0x03f; |
else |
return 0x0100; // ERR -- invalid code |
} |
|
int TTYBUS::lclreadcode(char *buf, int len) { |
char *sp, *dp; |
int nr, ret; |
|
nr = m_dev->read(buf, len); |
m_total_nread += nr; |
ret = nr; sp = buf; dp = buf; |
for(int i=0; i<nr; i++) { |
if (chardec(*sp)&(~0x3f)) { |
ret--; // Skip this value, not a valid codeword |
sp++; |
} else { |
*sp++ = *dp++; |
} |
} return ret; |
} |
|
void TTYBUS::bufalloc(int len) { |
if ((m_buf)&&(m_buflen >= len)) |
return; |
if (m_buf) |
delete[] m_buf; |
m_buflen = (len&(-0x3f))+0x40; |
m_buf = new char[m_buflen]; |
} |
|
void TTYBUS::encode(const int hb, const BUSW val, char *buf) const { |
buf[0] = charenc( (hb<<2)|((val>>30)&0x03) ); |
buf[1] = charenc( (val>>24)&0x3f); |
buf[2] = charenc( (val>>18)&0x3f); |
buf[3] = charenc( (val>>12)&0x3f); |
buf[4] = charenc( (val>> 6)&0x3f); |
buf[5] = charenc( (val )&0x3f); |
} |
|
unsigned TTYBUS::decodestr(const char *buf) const { |
unsigned r; |
|
r = chardec(buf[0]) & 0x03; |
r = (r<<6) | (chardec(buf[1]) & 0x03f); |
r = (r<<6) | (chardec(buf[2]) & 0x03f); |
r = (r<<6) | (chardec(buf[3]) & 0x03f); |
r = (r<<6) | (chardec(buf[4]) & 0x03f); |
r = (r<<6) | (chardec(buf[5]) & 0x03f); |
|
return r; |
} |
|
int TTYBUS::decodehex(const char hx) const { |
if ((hx >= '0')&&(hx <= '9')) |
return hx-'0'; |
else if ((hx >= 'A')&&(hx <= 'Z')) |
return hx-'A'+10; |
else if ((hx >= 'a')&&(hx <= 'z')) |
return hx-'a'+10; |
else |
return 0; |
} |
|
void TTYBUS::writeio(const BUSW a, const BUSW v) { |
|
writev(a, 0, 1, &v); |
m_lastaddr = a; m_addr_set = true; |
} |
|
void TTYBUS::writev(const BUSW a, const int p, const int len, const BUSW *buf) { |
char *ptr; |
|
// Allocate a buffer of six bytes per word, one for addr, plus |
// six more |
bufalloc((len+2)*6); |
|
DBGPRINTF("WRITEV(%08x,%d,#%d,0x%08x ...)\n", a, p, len, buf[0]); |
// Encode the address |
ptr = encode_address(a); |
m_lastaddr = a; m_addr_set = true; |
|
for(int i=0; i<len; i++) { |
BUSW val = buf[i]; |
|
int caddr = 0; |
// Let's try compression |
for(int i=1; i<256; i++) { |
unsigned tstaddr; |
tstaddr = (m_wraddr - i) & 0x0ff; |
if ((!m_wrloaded)&&(tstaddr > (unsigned)m_wraddr)) |
break; |
if (m_writetbl[tstaddr] == val) { |
caddr = ( m_wraddr- tstaddr ) & 0x0ff; |
break; |
} |
} |
|
if (caddr != 0) |
DBGPRINTF("WR[%08x] = %08x (= TBL[%4x] <= %4x)\n", m_lastaddr, val, caddr, m_wraddr); |
else |
DBGPRINTF("WR[%08x] = %08x\n", m_lastaddr, val); |
|
if (caddr != 0) { |
*ptr++ = charenc( (((caddr>>6)&0x03)<<1) + (p?1:0) + 0x010); |
*ptr++ = charenc( caddr &0x3f ); |
|
} else { |
// For testing, let's start just doing this the hard way |
*ptr++ = charenc( (((val>>30)&0x03)<<1) + (p?1:0) + 0x018); |
*ptr++ = charenc( (val>>24)&0x3f); |
*ptr++ = charenc( (val>>18)&0x3f); |
*ptr++ = charenc( (val>>12)&0x3f); |
*ptr++ = charenc( (val>> 6)&0x3f); |
*ptr++ = charenc( (val )&0x3f); |
|
m_writetbl[m_wraddr++] = val; |
m_wraddr &= 0x0ff; |
if (m_wraddr == 0) { |
m_wrloaded = true; |
} |
} |
|
if (p == 1) m_lastaddr++; |
} |
// *ptr++ = charenc(0x2e); |
*ptr++ = '\n'; *ptr = '\0'; |
m_dev->write(m_buf, ptr-m_buf); |
|
DBGPRINTF(">> %s\n", m_buf); |
DBGPRINTF("WR: LAST ADDRESS LEFT AT %08x\n", m_lastaddr); |
} |
|
void TTYBUS::writez(const BUSW a, const int len, const BUSW *buf) { |
int ln = len; |
const TTYBUS::BUSW *bptr = buf; |
TTYBUS::BUSW addr = a; |
|
while((unsigned)ln > MAXWRLEN) { |
writev(addr, 0, MAXWRLEN, bptr); |
bptr += MAXWRLEN; |
ln -= MAXWRLEN; |
// addr += MAXWRLEN; |
} if ((unsigned)ln > 0) |
writev(addr, 0, ln, bptr); |
} |
|
void TTYBUS::writei(const BUSW a, const int len, const BUSW *buf) { |
int ln = len; |
const TTYBUS::BUSW *bptr = buf; |
TTYBUS::BUSW addr = a; |
|
while((unsigned)ln > MAXWRLEN) { |
writev(addr, 1, MAXWRLEN, bptr); |
bptr += MAXWRLEN; |
ln -= MAXWRLEN; |
addr += MAXWRLEN; |
} if ((unsigned)ln > 0) |
writev(addr, 1, ln, bptr); |
} |
|
TTYBUS::BUSW TTYBUS::readio(const TTYBUS::BUSW a) { |
BUSW v; |
|
// I/O reads are now the same as vector reads, but with a vector length |
// of one. |
DBGPRINTF("READIO(0x%08x)\n", a); |
try { |
readv(a, 0, 1, &v); |
} catch(BUSERR b) { |
throw BUSERR(a); |
} |
|
if (m_lastaddr != a) { |
DBGPRINTF("LAST-ADDR MIS-MATCH: (RCVD) %08x != %08x (XPECTED)\n", m_lastaddr, a); |
m_addr_set = false; |
|
exit(-3); |
} |
|
return v; |
} |
|
char *TTYBUS::encode_address(const TTYBUS::BUSW a) { |
TTYBUS::BUSW addr = a; |
char *ptr = m_buf; |
|
// #warning DEBUG_APPROACH |
// encode(0, addr, ptr); |
// return ptr+6; |
|
if ((m_addr_set)&&(a == m_lastaddr)) |
return ptr; |
|
if (m_addr_set) { |
// Encode a difference address |
int diffaddr = addr - m_lastaddr; |
ptr = m_buf; |
if ((diffaddr >= -32)&&(diffaddr < 32)) { |
*ptr++ = charenc(0x09); |
*ptr++ = charenc(diffaddr & 0x03f); |
} else if ((diffaddr >= -2048)&&(diffaddr < 2048)) { |
*ptr++ = charenc(0x0b); |
*ptr++ = charenc((diffaddr>>6) & 0x03f); |
*ptr++ = charenc( diffaddr & 0x03f); |
} else if ((diffaddr >= -(1<<17))&&(diffaddr < (1<<17))) { |
*ptr++ = charenc(0x0d); |
*ptr++ = charenc((diffaddr>>12) & 0x03f); |
*ptr++ = charenc((diffaddr>> 6) & 0x03f); |
*ptr++ = charenc( diffaddr & 0x03f); |
} else if ((diffaddr >= -(1<<23))&&(diffaddr < (1<<23))) { |
*ptr++ = charenc(0x0d); |
*ptr++ = charenc((diffaddr>>18) & 0x03f); |
*ptr++ = charenc((diffaddr>>12) & 0x03f); |
*ptr++ = charenc((diffaddr>> 6) & 0x03f); |
*ptr++ = charenc( diffaddr & 0x03f); |
} |
*ptr = '\0'; |
DBGPRINTF("DIF-ADDR: (%ld) \'%s\'\n", ptr-m_buf, m_buf); |
} |
|
{ |
// Encode an absolute (low memory) address |
// Prefer absolute address encoding over differential encoding, |
// when both encodings encode the same address, and when both |
// encode the address in the same number of words |
if ((addr <= 0x03f)&&((ptr == m_buf)||(ptr >= &m_buf[2]))) { |
ptr = m_buf; |
*ptr++ = charenc(0x08); |
*ptr++ = charenc(addr); |
} else if((addr <= 0x0fff)&&((ptr == m_buf)||(ptr >= &m_buf[3]))) { |
DBGPRINTF("Setting ADDR.3 to %08x\n", addr); |
ptr = m_buf; |
*ptr++ = charenc(0x0a); |
*ptr++ = charenc((addr>> 6) & 0x03f); |
*ptr++ = charenc( addr & 0x03f); |
} else if((addr <= 0x03ffff)&&((ptr == m_buf)||(ptr >= &m_buf[4]))) { |
DBGPRINTF("Setting ADDR.4 to %08x\n", addr); |
ptr = m_buf; |
*ptr++ = charenc(0x0c); |
*ptr++ = charenc((addr>>12) & 0x03f); |
*ptr++ = charenc((addr>> 6) & 0x03f); |
*ptr++ = charenc( addr & 0x03f); |
} else if((addr <= 0x0ffffff)&&((ptr == m_buf)||(ptr >= &m_buf[5]))) { |
DBGPRINTF("Setting ADDR.5 to %08x\n", addr); |
ptr = m_buf; |
*ptr++ = charenc(0x0e); |
*ptr++ = charenc((addr>>18) & 0x03f); |
*ptr++ = charenc((addr>>12) & 0x03f); |
*ptr++ = charenc((addr>> 6) & 0x03f); |
*ptr++ = charenc( addr & 0x03f); |
} else if (ptr == m_buf) { // Send our address prior to any read |
// ptr = m_buf; |
encode(0, addr, ptr); |
ptr+=6; |
} |
} |
|
*ptr = '\0'; |
DBGPRINTF("ADDR-CMD: (%ld) \'%s\'\n", ptr-m_buf, m_buf); |
m_rdaddr = 0; |
|
return ptr; |
} |
|
char *TTYBUS::readcmd(const int inc, const int len, char *buf) { |
char *ptr = buf; |
|
DBGPRINTF("READCMD: LEN = %d\n", len); |
assert(len < 520); |
assert(len > 0); |
|
if ((len < 8)||((len == 8)&&(inc))) { |
*ptr++ = charenc(0x20 + (((len-1)&0x07)<<1) + (inc?1:0)); |
} else { |
*ptr++ = charenc(0x30 + (((len-8)>>5)&0x0e) + (inc?1:0)); |
*ptr++ = charenc( (len-8) & 0x03f); |
} |
|
return ptr; |
} |
|
void TTYBUS::readv(const TTYBUS::BUSW a, const int inc, const int len, TTYBUS::BUSW *buf) { |
const int READAHEAD = MAXRDLEN/2, READBLOCK=MAXRDLEN/2; |
int cmdrd = 0, nread = 0; |
// TTYBUS::BUSW addr = a; |
char *ptr = m_buf; |
|
if (len <= 0) |
return; |
DBGPRINTF("READV(%08x,%d,#%4d)\n", a, inc, len); |
|
ptr = encode_address(a); |
try { |
while(cmdrd < len) { |
// ptr = m_buf; |
do { |
int nrd = len-cmdrd; |
if (nrd > READBLOCK) |
nrd = READBLOCK; |
if (cmdrd-nread + nrd>READAHEAD+READBLOCK) |
nrd = READAHEAD+READBLOCK-(cmdrd-nread); |
ptr = readcmd(inc, nrd, ptr); |
cmdrd += nrd; |
} while((cmdrd-nread < READAHEAD+READBLOCK)&&(cmdrd< len)); |
|
*ptr++ = '\n'; *ptr = '\0'; |
m_dev->write(m_buf, (ptr-m_buf)); |
|
while(nread<(cmdrd-READAHEAD)) { |
buf[nread++] = readword(); |
} ptr = m_buf; |
} while(nread<len) { |
buf[nread++] = readword(); |
} |
} catch(BUSERR b) { |
throw BUSERR(a+((inc)?nread:0)); |
} |
|
if ((unsigned)m_lastaddr != (a+((inc)?(len):0))) { |
DBGPRINTF("TTYBUS::READV(a=%08x,inc=%d,len=%4x,x) ERR: (Last) %08x != %08x + %08x (Expected)\n", a, inc, len, m_lastaddr, a, (inc)?(len):0); |
printf("TTYBUS::READV(a=%08x,inc=%d,len=%4x,x) ERR: (Last) %08x != %08x + %08x (Expected)\n", a, inc, len, m_lastaddr, a, (inc)?(len):0); |
sleep(1); |
assert((int)m_lastaddr == (a+(inc)?(len):0)); |
exit(-3); |
} |
} |
|
void TTYBUS::readi(const TTYBUS::BUSW a, const int len, TTYBUS::BUSW *buf) { |
readv(a, 1, len, buf); |
} |
|
void TTYBUS::readz(const TTYBUS::BUSW a, const int len, TTYBUS::BUSW *buf) { |
readv(a, 0, len, buf); |
} |
|
TTYBUS::BUSW TTYBUS::readword(void) { |
TTYBUS::BUSW val = 0; |
int nr; |
unsigned sixbits; |
|
DBGPRINTF("READ-WORD()\n"); |
|
bool found_start = false; |
do { |
// Blocking read (for now) |
do { |
nr = lclreadcode(&m_buf[0], 1); |
} while (nr < 1); |
|
sixbits = chardec(m_buf[0]); |
|
if (sixbits&(~0x03f)) { |
// Ignore new lines, unprintables, and characters |
// not a part of our code |
; |
} else if (sixbits < 6) { |
switch(sixbits) { |
case 0: break; // Idle -- ignore |
case 1: break; // Idle, but the bus is busy |
case 2: break; // Write acknowledgement, ignore it here |
case 3: |
m_bus_err = true; |
throw BUSERR(0); |
break; |
case 4: |
m_interrupt_flag = true; |
break; |
case 5: |
m_bus_err = true; |
throw BUSERR(0); |
break; |
} |
} else if (0x08 == (sixbits & 0x3c)) { // Set 32-bit address |
do { |
nr += lclreadcode(&m_buf[nr], 6-nr); |
} while (nr < 6); |
|
val = chardec(m_buf[0]) & 0x03; |
val = (val<<6) | (chardec(m_buf[1]) & 0x03f); |
val = (val<<6) | (chardec(m_buf[2]) & 0x03f); |
val = (val<<6) | (chardec(m_buf[3]) & 0x03f); |
val = (val<<6) | (chardec(m_buf[4]) & 0x03f); |
val = (val<<6) | (chardec(m_buf[5]) & 0x03f); |
|
m_addr_set = true; |
m_lastaddr = val; |
|
DBGPRINTF("RCVD ADDR: 0x%08x\n", val); |
} else if (0x0c == (sixbits & 0x03c)) { // Set 32-bit address,compressed |
int nw = (sixbits & 0x03) + 2; |
do { |
nr += lclreadcode(&m_buf[nr], nw-nr); |
} while (nr < nw); |
|
if (nw == 2) { |
val = chardec(m_buf[1]); |
} else if (nw == 3) { |
val = chardec(m_buf[1]); |
val = (val<<6) | (chardec(m_buf[2]) & 0x03f); |
} else if (nw == 4) { |
val = chardec(m_buf[1]); |
val = (val<<6) | (chardec(m_buf[2]) & 0x03f); |
val = (val<<6) | (chardec(m_buf[3]) & 0x03f); |
} else { // if (nw == 5) |
val = chardec(m_buf[1]); |
val = (val<<6) | (chardec(m_buf[2]) & 0x03f); |
val = (val<<6) | (chardec(m_buf[3]) & 0x03f); |
val = (val<<6) | (chardec(m_buf[4]) & 0x03f); |
} |
|
m_addr_set = true; |
m_lastaddr = val; |
DBGPRINTF("RCVD ADDR: 0x%08x (%d bytes)\n", val, nw+1); |
} else |
found_start = true; |
} while(!found_start); |
|
int rdaddr; |
|
DBGPRINTF("READ-WORD() -- sixbits = %02x\n", sixbits); |
if (0x06 == (sixbits & 0x03e)) { // Tbl read, last value |
rdaddr = (m_rdaddr-1)&0x03ff; |
val = m_readtbl[rdaddr]; |
m_lastaddr += (sixbits&1); |
DBGPRINTF("READ-WORD() -- repeat last value, %08x\n", val); |
} else if (0x10 == (sixbits & 0x030)) { // Tbl read, up to 521 into past |
int idx; |
do { |
nr += lclreadcode(&m_buf[nr], 2-nr); |
} while (nr < 2); |
|
idx = (chardec(m_buf[0])>>1) & 0x07; |
idx = ((idx<<6) | (chardec(m_buf[1]) & 0x03f)) + 2 + 8; |
rdaddr = (m_rdaddr-idx)&0x03ff; |
val = m_readtbl[rdaddr]; |
m_lastaddr += (sixbits&1); |
DBGPRINTF("READ-WORD() -- long table value[%3d], %08x\n", idx, val); |
} else if (0x20 == (sixbits & 0x030)) { // Tbl read, 2-9 into past |
rdaddr = (m_rdaddr - (((sixbits>>1)&0x07)+2)) & 0x03ff; |
val = m_readtbl[rdaddr]; |
m_lastaddr += (sixbits&1); |
DBGPRINTF("READ-WORD() -- short table value[%3d], %08x\n", rdaddr, val); |
} else if (0x38 == (sixbits & 0x038)) { // Raw read |
DBGPRINTF("READ-WORD() -- RAW-READ, nr = %d\n", nr); |
do { |
nr += lclreadcode(&m_buf[nr], 6-nr); |
} while (nr < 6); |
|
val = (chardec(m_buf[0])>>1) & 0x03; |
val = (val<<6) | (chardec(m_buf[1]) & 0x03f); |
val = (val<<6) | (chardec(m_buf[2]) & 0x03f); |
val = (val<<6) | (chardec(m_buf[3]) & 0x03f); |
val = (val<<6) | (chardec(m_buf[4]) & 0x03f); |
val = (val<<6) | (chardec(m_buf[5]) & 0x03f); |
|
m_readtbl[m_rdaddr++] = val; m_rdaddr &= 0x03ff; |
m_lastaddr += (sixbits&1); |
DBGPRINTF("READ-WORD() -- RAW-READ %02x:%02x:%02x:%02x:%02x:%02x -- %08x\n", |
m_buf[0], m_buf[1], m_buf[2], m_buf[3], |
m_buf[4], m_buf[5], val); |
} else |
DBGPRINTF("READ-WORD() -- Unknown character, %02x\n", sixbits); |
|
return val; |
} |
|
void TTYBUS::usleep(unsigned ms) { |
if (m_dev->poll(ms)) { |
int nr; |
nr = m_dev->read(m_buf, 16); |
if (nr == 0) { |
// Connection closed, let it drop |
DBGPRINTF("Connection closed!!\n"); |
m_dev->close(); |
exit(-1); |
} for(int i=0; i<nr; i++) { |
if (m_buf[i] == TTYC_INT) { |
m_interrupt_flag = true; |
DBGPRINTF("!!!!!!!!!!!!!!!!! ----- INTERRUPT!\n"); |
} else if (m_buf[i] == TTYC_IDLE) { |
DBGPRINTF("Interface is now idle\n"); |
} else if (m_buf[i] == TTYC_WRITE) { |
} else if (m_buf[i] == TTYC_RESET) { |
DBGPRINTF("Bus was RESET!\n"); |
} else if (m_buf[i] == TTYC_ERR) { |
DBGPRINTF("Bus error\n"); |
} else if (m_buf[i] == TTYC_BUSY) { |
DBGPRINTF("Interface is ... busy ??\n"); |
} |
// else if (m_buf[nr] == 'Q') |
// else if (m_buf[nr] == 'W') |
// else if (m_buf[nr] == '\n') |
} |
} |
} |
|
void TTYBUS::wait(void) { |
if (m_interrupt_flag) |
DBGPRINTF("INTERRUPTED PRIOR TO WAIT()\n"); |
do { |
usleep(200); |
} while(!m_interrupt_flag); |
} |
|
// TTYBUS: 3503421 ~= 3.3 MB, stopwatch = 1:18.5 seconds, vs 53.8 secs |
// If you issue two 512 word reads at once, time drops to 41.6 secs. |
// PORTBUS: 6408320 ~= 6.1 MB, ... 26% improvement, 53 seconds real time |
|
/sw/host/flashdrvr.cpp
40,7 → 40,7
#include <signal.h> |
#include <assert.h> |
|
#include "port.h" |
#include "devbus.h" |
#include "regdefs.h" |
#include "flashdrvr.h" |
|
133,9 → 133,10
// command immediately. As soon as the write completes the read will |
// begin sending commands back. This allows us to recover the lost |
// time between the interrupt and the next command being received. |
if ((!HIGH_SPEED)||(!verify_write)) { |
flwait(); |
} if (verify_write) { |
flwait(); |
// if ((!HIGH_SPEED)||(!verify_write)) { } |
if (verify_write) { |
// printf("Attempting to verify page\n"); |
// NOW VERIFY THE PAGE |
m_fpga->readi(addr, len, buf); |
for(unsigned i=0; i<len; i++) { |
145,7 → 146,7
i, buf[i], data[i], i+addr); |
return false; |
} |
} |
} // printf("\nVerify success\n"); |
} return true; |
} |
|
194,21 → 195,26
continue; // This sector already matches |
|
// Just erase anyway |
if ((need_erase)&&(!erase_sector(s, verify))) { |
printf("SECTOR ERASE FAILED!\n"); |
return false; |
} else if (!need_erase) |
if (!need_erase) |
printf("NO ERASE NEEDED\n"); |
else { |
printf("ERASING SECTOR %08x\n", s); |
newv = (s<addr) ? addr : s; |
if (!erase_sector(s, verify)) { |
printf("SECTOR ERASE FAILED!\n"); |
return false; |
} newv = (s<addr) ? addr : s; |
} |
for(unsigned p=newv; (p<s+SECTORSZ)&&(p<addr+len); p=PAGEOF(p+PGLEN)) |
if (!write_page(p, (p+PGLEN<addr+len) |
?((PAGEOF(p)!=PAGEOF(p+PGLEN-1))?(PAGEOF(p+PGLEN-1)-p):PGLEN) |
:(addr+len-p), &data[p-addr]), verify) { |
for(unsigned p=newv; (p<s+SECTORSZ)&&(p<addr+len); p=PAGEOF(p+PGLEN)) { |
unsigned start = p, len = addr+len-start; |
|
// BUT! if we cross page boundaries, we need to clip |
// our results to the page boundary |
if (PAGEOF(start+len-1)!=PAGEOF(start)) |
len = PAGEOF(start+PGLEN)-start; |
if (!write_page(start, len, &data[p-addr], verify)) { |
printf("WRITE-PAGE FAILED!\n"); |
return false; |
} |
} |
} |
|
/sw/host/Makefile
1,11 → 1,12
all: |
PROGRAMS := wbregs |
PROGRAMS := wbregs readflash zipload |
all: $(PROGRAMS) |
|
CXX := g++ |
OBJDIR := obj-pc |
BUSSRCS:= deppbus.cpp regdefs.cpp |
SOURCES:= wbregs.cpp # flashload.cpp/ziprun.cpp |
# BUSSRCS:= deppbus.cpp regdefs.cpp |
BUSSRCS:= deppi.cpp regdefs.cpp llcomms.cpp ttybus.cpp |
SOURCES:= wbregs.cpp readflash.cpp zipload.cpp flashdrvr.cpp # flashload.cpp/ziprun.cpp |
ADEPT := ../../../refs/digilent.adept.sdk_2.3.1 |
HEADERS:= deppbus.h devbus.h flashdrvr.h regdefs.h twoc.h |
OBJECTS:= $(addprefix $(OBJDIR)/,$(subst .cpp,.o,$(SOURCES))) |
24,9 → 25,15
wbregs: $(OBJDIR)/wbregs.o $(BUSOBJS) |
$(CXX) $(CFLAGS) $^ $(LIBS) -o $@ |
|
readflash: $(OBJDIR)/readflash.o $(BUSOBJS) |
$(CXX) $(CFLAGS) $^ $(LIBS) -o $@ |
|
zipload: $(OBJDIR)/zipload.o $(OBJDIR)/flashdrvr.o $(BUSOBJS) |
$(CXX) $(CFLAGS) $^ $(LIBS) -lelf -o $@ |
|
define build-depends |
@echo "Building dependency file(s)" |
@$(CXX) $(CFLAGS) -MM $(SOURCES) > $(OBJDIR)/xdepends.txt |
@$(CXX) $(CFLAGS) -MM $(SOURCES) $(BUSSRCS) > $(OBJDIR)/xdepends.txt |
@sed -e 's/^.*.o: /$(OBJDIR)\/&/' < $(OBJDIR)/xdepends.txt > $(OBJDIR)/depends.txt |
@rm $(OBJDIR)/xdepends.txt |
endef |
/sw/host/devbus.h
2,7 → 2,7
// |
// Filename: devbus.h |
// |
// Project: XuLA2 board |
// Project: CMod S6 System on a Chip, ZipCPU demonstration project |
// |
// Purpose: The purpose of this file is to document an interface which |
// any device with a bus, whether it be implemented over a UART, |
22,7 → 22,7
// |
//////////////////////////////////////////////////////////////////////////////// |
// |
// Copyright (C) 2015, Gisselquist Technology, LLC |
// Copyright (C) 2015-2016, 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 |
34,6 → 34,11
// 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 |
// |
/sw/Makefile
0,0 → 1,63
##############################################################################// |
## |
## Filename: Makefile |
## |
## Project: CMod S6 System on a Chip, ZipCPU demonstration project |
## |
## Purpose: A speedbump on the way to building the software for the various |
## support directories--simply coordinating that. This makefile |
## allows the prior directory to issue a make in this directory, while |
## not needing to worry about subdirectories--which this file handles. |
## |
## Creator: Dan Gisselquist, Ph.D. |
## Gisselquist Technology, LLC |
## |
##############################################################################// |
## |
## Copyright (C) 2015-2016, 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 |
## |
## |
##############################################################################// |
## |
## |
.PHONY: all |
all: host dev zipos |
|
.PHONY: host dev zipos clean depends |
|
host: |
@bash -c 'if [ -e host/Makefile ]; then make --no-print-directory -C host; fi' |
dev: |
@bash -c 'if [ -e dev/Makefile ]; then make --no-print-directory -C dev; fi' |
zipos: |
@bash -c 'if [ -e zipos/Makefile ]; then make --no-print-directory -C zipos; fi' |
|
clean: |
@bash -c 'if [ -e host/Makefile ]; then make --no-print-directory -C host clean; fi' |
@bash -c 'if [ -e dev/Makefile ]; then make --no-print-directory -C dev clean; fi' |
@bash -c 'if [ -e zipos/Makefile ]; then make --no-print-directory -C zipos clean; fi' |
|
depends: |
@bash -c 'if [ -e host/Makefile ]; then make --no-print-directory -C host depends; fi' |
@bash -c 'if [ -e dev/Makefile ]; then make --no-print-directory -C dev depends; fi' |
@bash -c 'if [ -e zipos/Makefile ]; then make --no-print-directory -C zipos depends; fi' |
|
|
/Makefile
38,7 → 38,7
## |
## |
.PHONY: all |
all: datestamp archive |
all: datestamp archive rtl sw |
# BENCH := `find bench -name Makefile` `find bench -name "*.cpp"` `find bench -name "*.h"` |
BENCH := |
RTL := `find rtl -name "*.v"` `find rtl -name Makefile` |
58,13 → 58,29
@bash -c 'if [ ! -e $(YYMMDD)-build.v ]; then rm 20??????-build.v; perl mkdatev.pl > $(YYMMDD)-build.v; rm -f rtl/builddate.v; fi' |
@bash -c 'if [ ! -e rtl/builddate.v ]; then cd rtl; cp ../$(YYMMDD)-build.v builddate.v; fi' |
|
.PHONY: rtl |
rtl: |
@make --no-print-directory -C rtl |
|
.PHONY: sw |
sw: |
@make --no-print-directory -C sw |
|
.PHONY: doc |
doc: |
@make --no-print-directory -C doc |
|
.PHONY: bench |
bench: rtl |
@make --no-print-directory -C bench/cpp |
|
.PHONY: archive |
archive: |
tar --transform s,^,$(YYMMDD)-s6/, -chjf $(YYMMDD)-xula.tjz $(BENCH) $(SW) $(RTL) $(NOTES) $(PROJ) $(BIN) $(CONSTRAINTS) |
tar --transform s,^,$(YYMMDD)-s6/, -chjf $(YYMMDD)-s6.tjz $(BENCH) $(SW) $(RTL) $(NOTES) $(PROJ) $(BIN) $(CONSTRAINTS) |
|
# .PHONY: bit |
# bit: |
# cd xilinx ; make xula.bit |
# make --no-print-directory -C xilinx toplevel.bit |
|
axload: |
djtgcfg enum |
/cmod.ucf
94,112 → 94,58
NET "o_pwm_shutdown_n" LOC = "L2" | IOSTANDARD = LVCMOS33 | PULLUP; |
NET "o_pwm_gain" LOC = "M1" | IOSTANDARD = LVCMOS33 | PULLUP; |
# I2C |
NET "io_scl" LOC = "K2" | IOSTANDARD = LVCMOS33 | PULLUP; # io_scl, PIO44 |
NET "io_sda" LOC = "L1" | IOSTANDARD = LVCMOS33 | PULLUP; # io_sda, PIO45 |
NET "io_scl" LOC = "E14" | IOSTANDARD = LVCMOS33 | PULLUP; # io_scl, PIO44 |
NET "io_sda" LOC = "G13" | IOSTANDARD = LVCMOS33 | PULLUP; # io_sda, PIO45 |
|
# |
# o_gpio<0> and o_gpio<1> have been borrowed for io_scl and io_sda, hence we |
# start our count here at 2 |
# |
NET "o_gpio<2>" LOC = "N12" | IOSTANDARD = LVCMOS33; # display o_mosi |
NET "o_gpio<3>" LOC = "L14" | IOSTANDARD = LVCMOS33; # display o_sck |
NET "o_gpio<4>" LOC = "L13" | IOSTANDARD = LVCMOS33; # display o_ss |
NET "o_gpio<5>" LOC = "K14" | IOSTANDARD = LVCMOS33; |
NET "o_gpio<6>" LOC = "K13" | IOSTANDARD = LVCMOS33; |
NET "o_gpio<7>" LOC = "J14" | IOSTANDARD = LVCMOS33; |
NET "o_gpio<8>" LOC = "J13" | IOSTANDARD = LVCMOS33; |
# NET "o_gpio<0>" LOC = "G13" | IOSTANDARD = LVCMOS33; # io_sda |
# NET "o_gpio<1>" LOC = "E14" | IOSTANDARD = LVCMOS33; # io_scl |
NET "o_gpio<2>" LOC = "D13" | IOSTANDARD = LVCMOS33; # display o_mosi |
NET "o_gpio<3>" LOC = "E13" | IOSTANDARD = LVCMOS33; # display o_sck |
NET "o_gpio<4>" LOC = "C13" | IOSTANDARD = LVCMOS33; # display o_ss |
NET "o_gpio<5>" LOC = "G14" | IOSTANDARD = LVCMOS33; |
NET "o_gpio<6>" LOC = "F13" | IOSTANDARD = LVCMOS33; |
NET "o_gpio<7>" LOC = "F14" | IOSTANDARD = LVCMOS33; |
NET "o_gpio<8>" LOC = "H13" | IOSTANDARD = LVCMOS33; |
NET "o_gpio<9>" LOC = "H14" | IOSTANDARD = LVCMOS33; |
NET "o_gpio<10>" LOC = "H13" | IOSTANDARD = LVCMOS33; |
NET "o_gpio<11>" LOC = "F14" | IOSTANDARD = LVCMOS33; |
NET "o_gpio<12>" LOC = "F13" | IOSTANDARD = LVCMOS33; |
NET "o_gpio<13>" LOC = "G14" | IOSTANDARD = LVCMOS33; |
NET "o_gpio<14>" LOC = "G13" | IOSTANDARD = LVCMOS33; |
NET "o_gpio<15>" LOC = "E14" | IOSTANDARD = LVCMOS33; |
NET "o_gpio<10>" LOC = "J13" | IOSTANDARD = LVCMOS33; |
NET "o_gpio<11>" LOC = "J14" | IOSTANDARD = LVCMOS33; |
NET "o_gpio<12>" LOC = "C1" | IOSTANDARD = LVCMOS33; |
NET "o_gpio<13>" LOC = "D1" | IOSTANDARD = LVCMOS33; |
NET "o_gpio<14>" LOC = "D2" | IOSTANDARD = LVCMOS33; |
NET "o_gpio<15>" LOC = "E1" | IOSTANDARD = LVCMOS33; |
|
# |
# As with the o_gpio wires, i_gpio<0> and i_gpio<1> have been borrowed for |
# io_scl and io_sda, hence we start our count here at 2 |
# |
# NET "i_gpio<0>" LOC = "A3" | IOSTANDARD = LVCMOS33; |
# NET "i_gpio<1>" LOC = "B3" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<2>" LOC = "P5" | IOSTANDARD = LVCMOS33; # display miso |
NET "i_gpio<3>" LOC = "D14" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<4>" LOC = "C1" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<5>" LOC = "D1" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<6>" LOC = "D2" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<7>" LOC = "E1" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<8>" LOC = "E2" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<9>" LOC = "F1" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<10>" LOC = "F2" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<11>" LOC = "H1" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<12>" LOC = "H2" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<13>" LOC = "G1" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<14>" LOC = "G2" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<15>" LOC = "J1" | IOSTANDARD = LVCMOS33; |
# NET "i_gpio<0>" LOC = "G13" | IOSTANDARD = LVCMOS33; # io_sda |
# NET "i_gpio<1>" LOC = "E14" | IOSTANDARD = LVCMOS33; # io_scl |
NET "i_gpio<2>" LOC = "D14" | IOSTANDARD = LVCMOS33; # display miso |
NET "i_gpio<3>" LOC = "E2" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<4>" LOC = "F1" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<5>" LOC = "F2" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<6>" LOC = "H1" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<7>" LOC = "H2" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<8>" LOC = "G1" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<9>" LOC = "G2" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<10>" LOC = "J1" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<11>" LOC = "J2" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<12>" LOC = "K1" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<13>" LOC = "K2" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<14>" LOC = "L1" | IOSTANDARD = LVCMOS33; |
NET "i_gpio<15>" LOC = "N12" | IOSTANDARD = LVCMOS33; |
|
NET "o_kp_col<0>" LOC = "J2" | IOSTANDARD = LVCMOS33 | PULLUP; |
NET "o_kp_col<1>" LOC = "K1" | IOSTANDARD = LVCMOS33 | PULLUP; |
NET "o_kp_col<2>" LOC = "P7" | IOSTANDARD = LVCMOS33 | PULLUP; |
NET "o_kp_col<3>" LOC = "D13" | IOSTANDARD = LVCMOS33 | PULLUP; |
NET "o_kp_col<0>" LOC = "P5" | IOSTANDARD = LVCMOS33 | PULLUP; |
NET "o_kp_col<1>" LOC = "N5" | IOSTANDARD = LVCMOS33 | PULLUP; |
NET "o_kp_col<2>" LOC = "N6" | IOSTANDARD = LVCMOS33 | PULLUP; |
NET "o_kp_col<3>" LOC = "P7" | IOSTANDARD = LVCMOS33 | PULLUP; |
|
NET "i_kp_row<0>" LOC = "E13" | IOSTANDARD = LVCMOS33 | PULLUP; |
NET "i_kp_row<1>" LOC = "N5" | IOSTANDARD = LVCMOS33 | PULLUP; |
NET "i_kp_row<2>" LOC = "P12" | IOSTANDARD = LVCMOS33 | PULLUP; |
NET "i_kp_row<3>" LOC = "N6" | IOSTANDARD = LVCMOS33 | PULLUP; |
NET "i_kp_row<0>" LOC = "L14" | IOSTANDARD = LVCMOS33 | PULLUP; |
NET "i_kp_row<1>" LOC = "L13" | IOSTANDARD = LVCMOS33 | PULLUP; |
NET "i_kp_row<2>" LOC = "K14" | IOSTANDARD = LVCMOS33 | PULLUP; |
NET "i_kp_row<3>" LOC = "K13" | IOSTANDARD = LVCMOS33 | PULLUP; |
|
# NET "PORTA<0>" LOC = "P5" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO01, i_uart |
# NET "PORTA<1>" LOC = "N5" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO02, o_uart |
# NET "PORTA<2>" LOC = "N6" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO03, io_scl |
# NET "PORTA<3>" LOC = "P7" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO04, io_sda |
# NET "PORTA<4>" LOC = "P12" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO05, o_pwm |
# NET "PORTA<5>" LOC = "N12" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO06 |
# NET "PORTA<6>" LOC = "L14" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO07 |
# NET "PORTA<7>" LOC = "L13" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO08 |
# |
# #B Input ports |
# NET "PORTB<0>" LOC = "K14" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO09 |
# NET "PORTB<1>" LOC = "K13" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO10 |
# NET "PORTB<2>" LOC = "J14" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO11 |
# NET "PORTB<3>" LOC = "J13" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO12 |
# NET "PORTB<4>" LOC = "H14" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO13 |
# NET "PORTB<5>" LOC = "H13" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO14 |
# NET "PORTB<6>" LOC = "F14" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO15 |
# NET "PORTB<7>" LOC = "F13" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO16 |
# |
# #C Input ports |
# NET "PORTC<0>" LOC = "G14" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO17 |
# NET "PORTC<1>" LOC = "G13" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO18 |
# NET "PORTC<2>" LOC = "E14" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO19 |
# NET "PORTC<3>" LOC = "E13" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO20 |
# NET "PORTC<4>" LOC = "D14" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO21 |
# NET "PORTC<5>" LOC = "D13" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO22 |
# NET "PORTC<6>" LOC = "C13" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO23 |
# |
# #D Output ports |
# NET "PORTD<0>" LOC = "A3" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO26 |
# NET "PORTD<1>" LOC = "B3" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO |
# NET "PORTD<2>" LOC = "A2" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO |
# NET "PORTD<3>" LOC = "B1" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO |
# NET "PORTD<4>" LOC = "C1" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO30 |
# NET "PORTD<5>" LOC = "D1" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO |
# NET "PORTD<6>" LOC = "D2" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO |
# NET "PORTD<7>" LOC = "E1" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO33 |
# |
# #E Output ports |
# NET "PORTE<0>" LOC = "E2" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO34 |
# NET "PORTE<1>" LOC = "F1" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO |
# NET "PORTE<2>" LOC = "F2" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO |
# NET "PORTE<3>" LOC = "H1" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO |
# NET "PORTE<4>" LOC = "H2" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO |
# NET "PORTE<5>" LOC = "G1" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO |
# NET "PORTE<6>" LOC = "G2" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO |
# NET "PORTE<7>" LOC = "J1" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO41 |
# |
# #F Unused ports |
# NET "PORTF<0>" LOC = "J2" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO42 |
# NET "PORTF<1>" LOC = "K1" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO |
# NET "PORTF<2>" LOC = "K2" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO44 |
# NET "PORTF<3>" LOC = "L1" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO45 |
# NET "PORTF<4>" LOC = "L2" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO46 |
# NET "PORTF<5>" LOC = "M1" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO47 |
# NET "PORTF<6>" LOC = "M2" | IOSTANDARD = LVCMOS33 | PULLUP; # PIO48 |