diff --git a/README.md b/README.md
index be77d37..fe930a7 100644
--- a/README.md
+++ b/README.md
@@ -41,6 +41,25 @@ Other inspirations were, among others, in no particular order:
- the Magic-1 by Bill Buzbee
- the OPC by revaldinho
+## October 2025 Update
+This update introduces a data cache for the Tridora-CPU. It is similar to the instruction cache
+as it caches the 16 bytes coming from the DRAM memory controller. It is a write-back cache, i.e.
+when a word inside the cached area is written, it updates the cache instead of invalidating it.
+
+This is important because there are many idioms in the stack machine assembly language where you
+store a local variable and then read it again (e.g. updating a loop variable).
+
+Since for most programs, the user stack and parts of the heap are inside the DRAM area, the data cache
+has a more noticable impact. In the benchmark program that was already used for the last update,
+the data cache results in a 50% improvement for the empty loop test. This is in comparison to the version
+without data cache but with the instruction cache, both running code out of DRAM.
+
+It is also noticable for compile times: With the data cache, compiling and assembling the
+"hello,world" program takes 16 seconds instead of 20. With a little tweak of the SD-Card controller
+that slightly increased the data transfer rate, the build time goes down to 15 seconds.
+
+Also, an audio controller was added that allows interrupt-driven sample playback via an AMP2 PMOD.
+
## April 2025 Update
The clock has been reduced to 77 MHz from 83 MHz. Apparently the design was at the limit and
timing problems were cropping up seemingly at random. Reducing the clock speed made some
@@ -62,7 +81,7 @@ on the emulator image.
- the [Hackaday project](https://hackaday.io/project/198324-tridora-cpu) (mostly copy-paste from this README)
- the [YouTube channel](https://www.youtube.com/@tridoracpu/videos) with some demo videos
- the [emulator](https://git.insignificance.de/slederer/-/packages/generic/tridoraemu/0.0.5/files/12) (source and windows binary)
-- the [FPGA bitstream](https://git.insignificance.de/slederer/-/packages/generic/tdr-bitstream/0.0.2/files/14) for the Arty-A7-35T board
+- the [FPGA bitstream](https://git.insignificance.de/slederer/-/packages/generic/tdr-bitstream/0.0.4/files/16) for the Arty-A7-35T board
- an [SD-card image](https://git.insignificance.de/slederer/-/packages/generic/tdr-cardimage/0.0.4/files/13)
Contact the author here: tridoracpu [at] insignificance.de
diff --git a/doc/mem.md b/doc/mem.md
index e24fbe2..f7dbc2b 100644
--- a/doc/mem.md
+++ b/doc/mem.md
@@ -34,3 +34,4 @@ Currently, only I/O slots 0-3 are being used.
| 1 | $880 | SPI-SD |
| 2 | $900 | VGA |
| 3 | $980 | IRQC |
+| 4 | $A00 | TDRAUDIO |
diff --git a/examples/fastfire.inc b/examples/fastfire.inc
new file mode 100644
index 0000000..bf0dce6
--- /dev/null
+++ b/examples/fastfire.inc
@@ -0,0 +1,5 @@
+const FIREWIDTH = 319; FIREHEIGHT = 79; (* keep in sync with fastfire.s! *)
+type FireBuf = array [0..FIREHEIGHT, 0..FIREWIDTH] of integer;
+
+procedure FastFireUpdate(var f:FireBuf); external;
+procedure FastFireDraw(var f:FireBuf;screenx, screeny:integer); external;
diff --git a/examples/fastfire.s b/examples/fastfire.s
new file mode 100644
index 0000000..f0e10e4
--- /dev/null
+++ b/examples/fastfire.s
@@ -0,0 +1,326 @@
+ ; width and height of the fire cell matrix
+ ; Be sure to sync this with fastfire.inc!
+ .EQU FIREWIDTH 319
+ .EQU FIREHEIGHT 79
+
+ ;
+ ; The cell matrix actually has one column
+ ; and one row more than FIREWIDTH and
+ ; FIREHEIGHT to handle the negative
+ ; X offsets when calculating new
+ ; cell values.
+ ; Likewise, there is one more row.
+ ; So rows are processed from 0 to FIREHEIGHT - 2
+ ; and columms from 1 to FIREWIDTH - 1.
+
+ ; cells considered for calculating new
+ ; value for cell O (reference cells):
+ ; .....O......
+ ; ....123.....
+ ; .....4......
+
+; args: pointer to fire cell buffer
+ .EQU FF_ROW_COUNT 0
+ .EQU FF_COL_COUNT 4
+ .EQU FF_ROW_OFFS 8
+ .EQU FF_OFFS1 12
+ .EQU FF_OFFS2 16
+ .EQU FF_OFFS3 20
+ .EQU FF_OFFS4 24
+ .EQU FF_CELL_PTR 28
+ .EQU FF_FS 32
+FASTFIREUPDATE:
+ FPADJ -FF_FS
+ STORE FF_CELL_PTR
+ LOADC FIREHEIGHT-1
+ STORE FF_ROW_COUNT
+
+ ; calculate offsets for reference cells
+ LOADC FIREWIDTH+1
+ SHL 2
+ DUP
+ STORE FF_ROW_OFFS ; offset to next row: WIDTH*4
+ DEC 4 ; offset to cell 1: row offset - 4
+ DUP
+ STORE FF_OFFS1
+ INC 4
+ DUP
+ STORE FF_OFFS2 ; offset to cell 2: + 4
+ INC 4
+ STORE FF_OFFS3 ; offset to cell 3: + 4
+ LOAD FF_ROW_OFFS
+ SHL 1 ; offset to cell 4: row offset * 2
+ STORE FF_OFFS4
+
+ ; start at column 1
+ LOAD FF_CELL_PTR
+ INC 4
+ STORE FF_CELL_PTR
+FF_ROW:
+ LOADC FIREWIDTH-1
+ STORE FF_COL_COUNT
+
+FF_COL:
+ LOAD FF_CELL_PTR
+ LOAD FF_OFFS1
+ ADD
+ LOADI
+
+ LOAD FF_CELL_PTR
+ LOAD FF_OFFS2
+ ADD
+ LOADI
+
+ LOAD FF_CELL_PTR
+ LOAD FF_OFFS3
+ ADD
+ LOADI
+
+ LOAD FF_CELL_PTR
+ LOAD FF_OFFS4
+ ADD
+ LOADI
+
+ ADD
+ ADD
+ ADD
+
+ SHR
+ SHR
+
+ ; if new cell value > 0, subtract 1 to cool down
+ DUP
+ CBRANCH.Z FF_SKIP
+ DEC 1
+FF_SKIP:
+ LOAD FF_CELL_PTR ; load cell ptr
+ SWAP ; swap with new value
+ STOREI 4 ; store with postincrement
+ STORE FF_CELL_PTR ; save new ptr value
+
+ LOAD FF_COL_COUNT ; decrement column count
+ DEC 1
+ DUP
+ STORE FF_COL_COUNT
+ CBRANCH.NZ FF_COL ; loop if col count <> 0
+
+ ; at the end of a row, go to next row
+ ; by adding 8 to the cell pointer,
+ ; skipping the first cell of the next row
+ LOAD FF_CELL_PTR
+ INC 8
+ STORE FF_CELL_PTR
+
+ LOAD FF_ROW_COUNT ; decrement row count
+ DEC 1
+ DUP
+ STORE FF_ROW_COUNT
+ CBRANCH.NZ FF_ROW ; loop if row count <> 0
+
+FF_EXIT:
+ FPADJ FF_FS
+ RET
+
+; framebuffer controller registers
+ .EQU FB_RA $900
+ .EQU FB_WA $901
+ .EQU FB_IO $902
+ .EQU FB_PS $903
+ .EQU FB_PD $904
+ .EQU FB_CTL $905
+ .EQU WORDS_PER_LINE 80
+
+; fire width in vmem words (strict left-to-right evaluation)
+ .EQU FFD_ROW_WORDS 1 + FIREWIDTH / 8
+
+; draw all fire cells
+; args: pointer to fire cell buffer, screen x, screen y
+ .EQU FFD_CELL_PTR 0
+ .EQU FFD_X 4
+ .EQU FFD_Y 8
+ .EQU FFD_ROW_COUNT 12
+ .EQU FFD_ROW_WORDCOUNT 16
+ .EQU FFD_VMEM_PTR 20
+ .EQU FFD_FS 24
+FASTFIREDRAW:
+ FPADJ -FFD_FS
+ STORE FFD_Y
+ STORE FFD_X
+ STORE FFD_CELL_PTR
+
+ ; calculate video memory addr
+ ; addr = y * 80 + X / 8
+ LOAD FFD_Y
+ SHL 2 ; y * 16
+ SHL 2
+ DUP
+ SHL 2 ; + y * 64
+ ADD ; = y * 80
+
+ LOAD FFD_X
+ SHR
+ SHR
+ SHR
+ ADD ; + x / 8
+
+ DUP
+ STORE FFD_VMEM_PTR
+ LOADC FB_WA ; set vmem write address
+ SWAP
+ STOREI
+ DROP
+
+ LOADC FIREHEIGHT + 1
+ STORE FFD_ROW_COUNT
+FFD_ROW:
+ LOADC FFD_ROW_WORDS
+ STORE FFD_ROW_WORDCOUNT
+
+ LOADC FB_WA ; set vmem write address
+ LOAD FFD_VMEM_PTR
+ STOREI
+ DROP
+
+FFD_WORD:
+ LOAD FFD_CELL_PTR ; load cell ptr
+ LOADC 0 ; vmem word, start with 0
+
+ ; leftmost pixel (0)
+ OVER ; [ cptr, vmemw, cptr ]
+ LOADI ; load cell value [ cptr, vmemw, cellval ]
+ SHR ; scale it down (from 7 bits to 4)
+ SHR
+ SHR ; [ cptr, vmemw, cellval shr 3 ]
+ OR ; [ cptr, vmemw ]
+ SWAP ; [ vmemw, cptr ]
+ INC 4 ; increment cell ptr on stack [ vmemw, cptr + 4 ]
+ SWAP ; [ cptr + 4, vmemw ]
+
+ SHL 2 ; move bits to left for next pixel
+ SHL 2
+
+ ; pixel 1
+ OVER
+ LOADI ; load cell value
+ SHR ; scale it down (from 7 bits to 4)
+ SHR
+ SHR
+ OR
+ SWAP
+ INC 4 ; increment cell ptr on stack
+ SWAP
+
+ SHL 2 ; move bits to left for next pixel
+ SHL 2
+
+ ; pixel 2
+ OVER
+ LOADI ; load cell value
+ SHR ; scale it down (from 7 bits to 4)
+ SHR
+ SHR
+ OR
+ SWAP
+ INC 4 ; increment cell ptr on stack
+ SWAP
+
+ SHL 2 ; move bits to left for next pixel
+ SHL 2
+
+ ; pixel 3
+ OVER
+ LOADI ; load cell value
+ SHR ; scale it down (from 7 bits to 4)
+ SHR
+ SHR
+ OR
+ SWAP
+ INC 4 ; increment cell ptr on stack
+ SWAP
+
+ SHL 2 ; move bits to left for next pixel
+ SHL 2
+
+ ; pixel 4
+ OVER
+ LOADI ; load cell value
+ SHR ; scale it down (from 7 bits to 4)
+ SHR
+ SHR
+ OR
+ SWAP
+ INC 4 ; increment cell ptr on stack
+ SWAP
+
+ SHL 2 ; move bits to left for next pixel
+ SHL 2
+
+ ; pixel 5
+ OVER
+ LOADI ; load cell value
+ SHR ; scale it down (from 7 bits to 4)
+ SHR
+ SHR
+ OR
+ SWAP
+ INC 4 ; increment cell ptr on stack
+ SWAP
+
+ SHL 2 ; move bits to left for next pixel
+ SHL 2
+
+ ; pixel 6
+ OVER
+ LOADI ; load cell value
+ SHR ; scale it down (from 7 bits to 4)
+ SHR
+ SHR
+ OR
+ SWAP
+ INC 4 ; increment cell ptr on stack
+ SWAP
+
+ SHL 2 ; move bits to left for next pixel
+ SHL 2
+
+ ; pixel 7
+ OVER
+ LOADI ; load cell value
+ SHR ; scale it down (from 7 bits to 4)
+ SHR
+ SHR
+ OR
+ SWAP
+ INC 4 ; increment cell ptr on stack
+ SWAP
+
+ ; store word to vmem
+ ; vmem write addr will autoincrement
+ LOADC FB_IO
+ SWAP
+ STOREI
+ DROP
+
+ STORE FFD_CELL_PTR
+
+ ; prepare for next word
+ LOAD FFD_ROW_WORDCOUNT
+ DEC 1
+ DUP
+ STORE FFD_ROW_WORDCOUNT
+ CBRANCH.NZ FFD_WORD
+
+ ; prepare for next row
+ LOAD FFD_VMEM_PTR
+ LOADC WORDS_PER_LINE
+ ADD
+ STORE FFD_VMEM_PTR
+
+ LOAD FFD_ROW_COUNT
+ DEC 1
+ DUP
+ STORE FFD_ROW_COUNT
+ CBRANCH.NZ FFD_ROW
+FFD_EXIT:
+ FPADJ FFD_FS
+ RET
diff --git a/examples/fire.pas b/examples/fire.pas
new file mode 100644
index 0000000..22f0217
--- /dev/null
+++ b/examples/fire.pas
@@ -0,0 +1,76 @@
+{$H1}
+{$S2}
+program fire;
+const MAXX = 30;
+ MAXY = 50;
+var firebuf: array [0..MAXY, 0..MAXX] of integer;
+
+ firepalette: array [0..15] of integer =
+ ( $FFA, $FF8, $FF4, $FF0, $FE0, $FD0, $FA0, $F90,
+ $F00, $E00, $D00, $A00, $800, $600, $300, $000);
+ x,y:integer;
+
+procedure createPalette;
+var i:integer;
+begin
+ for i := 15 downto 0 do
+ setpalette(15 - i, firepalette[i]);
+end;
+
+procedure fireItUp;
+var x,y:integer;
+begin
+ y := MAXY - 1;
+ for x := 1 to MAXX - 1 do
+ firebuf[y, x] := random and 127;
+end;
+
+procedure updateFire;
+var i,x,y:integer;
+begin
+ for y := 0 to MAXY - 2 do
+ for x := 1 to MAXX - 1 do
+ begin
+ i :=
+ ((firebuf[y + 1, x - 1]
+ + firebuf[y + 1, x]
+ + firebuf[y + 1, x + 1]
+ + firebuf[y + 2, x])
+ ) shr 2;
+ if i > 0 then
+ i := i - 1;
+ firebuf[y, x] := i;
+ end;
+end;
+
+procedure drawFire;
+var x, y, col:integer;
+begin
+ for y := 0 to MAXY - 1 do
+ begin
+ x := 0;
+ for col in firebuf[y] do
+ begin
+ putpixel(300 + x, 150 + y, col shr 3);
+ x := x + 1;
+ end;
+ end;
+end;
+
+begin
+ randomize;
+ initgraphics;
+ createPalette;
+ while not conavail do
+ begin
+ fireItUp;
+ updateFire;
+ drawFire;
+ end;
+
+ for y := 0 to MAXY do
+ begin
+ x := firebuf[y, 10];
+ drawline(0, y, x, y, 1);
+ end;
+end.
diff --git a/examples/fire2.pas b/examples/fire2.pas
new file mode 100644
index 0000000..72fb254
--- /dev/null
+++ b/examples/fire2.pas
@@ -0,0 +1,84 @@
+{$H1}
+{$S1}
+program fire2;
+uses fastfire;
+
+const MAXX = FIREWIDTH;
+ MAXY = FIREHEIGHT;
+
+var firecells: FireBuf;
+
+ firepalette: array [0..15] of integer =
+ { ( $FFA, $FF8, $FF4, $FF0, $FE0, $FD0, $FA0, $F90,
+ $F00, $E00, $D00, $A00, $800, $600, $300, $000); }
+ ( $FFA, $FFA, $FFA, $FFA, $FF0, $FF0, $FF0, $FF0,
+ $FF0, $FD0, $FA0, $C00, $A00, $700, $400, $000);
+ x,y:integer;
+
+procedure createPalette;
+var i:integer;
+begin
+ for i := 15 downto 0 do
+ setpalette(15 - i, firepalette[i]);
+end;
+
+procedure fireItUp;
+var x,y:integer;
+begin
+ y := MAXY - 1;
+ for x := 1 to MAXX - 1 do
+ firecells[y, x] := random and 127;
+end;
+
+
+procedure updateFire;
+var i,x,y:integer;
+begin
+ for y := 0 to MAXY - 2 do
+ for x := 1 to MAXX - 1 do
+ begin
+ i :=
+ ((firecells[y + 1, x - 1]
+ + firecells[y + 1, x]
+ + firecells[y + 1, x + 1]
+ + firecells[y + 2, x])
+ ) shr 2;
+ if i > 0 then
+ i := i - 1;
+ firecells[y, x] := i;
+ end;
+end;
+
+procedure drawFire;
+var x, y, col:integer;
+begin
+ for y := 0 to MAXY - 1 do
+ begin
+ x := 0;
+ for col in firecells[y] do
+ begin
+ putpixel(100 + x, 150 + y, col shr 3);
+ x := x + 1;
+ end;
+ end;
+end;
+
+begin
+ randomize;
+ initgraphics;
+ createPalette;
+ while not conavail do
+ begin
+ fireItUp;
+ FastFireUpdate(firecells);
+ { updateFire; }
+ FastFireDraw(firecells, 160, 100);
+ { drawFire; }
+ end;
+
+ for y := 0 to MAXY do
+ begin
+ x := firecells[y, 10];
+ drawline(0, y, x, y, 1);
+ end;
+end.
diff --git a/pcomp/emit.pas b/pcomp/emit.pas
index a201714..d440951 100644
--- a/pcomp/emit.pas
+++ b/pcomp/emit.pas
@@ -324,7 +324,9 @@ begin
rewindStringList(usedUnits);
while nextStringListItem(usedUnits, unitName) do
emitInclude(unitName + UnitSuffix2);
-
+ (* _END label needs to be word-aligned because
+ it is used as the start of the heap *)
+ emitIns('.ALIGN');
emitLabelRaw('_END');
end;
diff --git a/pcomp/sasm.pas b/pcomp/sasm.pas
index 1858f11..d032748 100644
--- a/pcomp/sasm.pas
+++ b/pcomp/sasm.pas
@@ -2056,6 +2056,9 @@ begin
operandValue := 0;
emitBlock(count, operandValue);
end
+ else
+ if lastToken.tokenText = '.ALIGN' then
+ alignOutput(wordSize)
else
errorExit2('Unrecognized directive', lastToken.tokenText);
end;
diff --git a/progs/xfer.pas b/progs/xfer.pas
index 13a7cc2..0d871d2 100644
--- a/progs/xfer.pas
+++ b/progs/xfer.pas
@@ -226,6 +226,7 @@ begin
if not invalid then
begin
open(xferFile, filename, ModeOverwrite);
+ blockNo := 0;
done := false;
repeat
serReadBlock(ok);
diff --git a/tridoracpu/tridoracpu.srcs/Arty-A7-35-Master.xdc b/tridoracpu/tridoracpu.srcs/Arty-A7-35-Master.xdc
index 2a33ae0..d2c3160 100644
--- a/tridoracpu/tridoracpu.srcs/Arty-A7-35-Master.xdc
+++ b/tridoracpu/tridoracpu.srcs/Arty-A7-35-Master.xdc
@@ -8,8 +8,8 @@ set_property -dict {PACKAGE_PIN E3 IOSTANDARD LVCMOS33} [get_ports clk]
create_clock -period 10.000 -name sys_clk_pin -waveform {0.000 5.000} -add [get_ports clk]
## Switches
-set_property -dict {PACKAGE_PIN A8 IOSTANDARD LVCMOS33} [get_ports sw0]
-set_property -dict {PACKAGE_PIN C11 IOSTANDARD LVCMOS33} [get_ports sw1]
+#set_property -dict {PACKAGE_PIN A8 IOSTANDARD LVCMOS33} [get_ports sw0]
+#set_property -dict {PACKAGE_PIN C11 IOSTANDARD LVCMOS33} [get_ports sw1]
#set_property -dict { PACKAGE_PIN C10 IOSTANDARD LVCMOS33 } [get_ports { sw[2] }]; #IO_L13N_T2_MRCC_16 Sch=sw[2]
#set_property -dict { PACKAGE_PIN A10 IOSTANDARD LVCMOS33 } [get_ports { sw[3] }]; #IO_L14P_T2_SRCC_16 Sch=sw[3]
@@ -34,7 +34,7 @@ set_property -dict {PACKAGE_PIN T9 IOSTANDARD LVCMOS33} [get_ports led2]
set_property -dict {PACKAGE_PIN T10 IOSTANDARD LVCMOS33} [get_ports led3]
## Buttons
-set_property -dict {PACKAGE_PIN D9 IOSTANDARD LVCMOS33} [get_ports btn0]
+#set_property -dict {PACKAGE_PIN D9 IOSTANDARD LVCMOS33} [get_ports btn0]
#set_property -dict { PACKAGE_PIN C9 IOSTANDARD LVCMOS33 } [get_ports { btn1 }]; #IO_L11P_T1_SRCC_16 Sch=btn[1]
#set_property -dict { PACKAGE_PIN B9 IOSTANDARD LVCMOS33 } [get_ports { btn[2] }]; #IO_L11N_T1_SRCC_16 Sch=btn[2]
#set_property -dict { PACKAGE_PIN B8 IOSTANDARD LVCMOS33 } [get_ports { btn[3] }]; #IO_L12P_T1_MRCC_16 Sch=btn[3]
diff --git a/tridoracpu/tridoracpu.srcs/stackcpu.v b/tridoracpu/tridoracpu.srcs/stackcpu.v
index 33b58ec..1d929f7 100644
--- a/tridoracpu/tridoracpu.srcs/stackcpu.v
+++ b/tridoracpu/tridoracpu.srcs/stackcpu.v
@@ -16,11 +16,11 @@ module stackcpu #(parameter ADDR_WIDTH = 32, WIDTH = 32,
output wire write_enable,
input wire mem_wait,
- output wire led1,
- output wire led2,
- output wire led3
+ output wire debug1,
+ output wire debug2,
+ output wire debug3
);
-
+
localparam EVAL_STACK_INDEX_WIDTH = 6;
wire reset = !rst;
@@ -90,7 +90,6 @@ module stackcpu #(parameter ADDR_WIDTH = 32, WIDTH = 32,
wire mem_write;
wire x_is_zero;
- // wire [WIDTH-1:0] y_plus_operand = Y + operand;
wire x_equals_y = X == Y;
wire y_lessthan_x = $signed(Y) < $signed(X);
@@ -105,16 +104,10 @@ module stackcpu #(parameter ADDR_WIDTH = 32, WIDTH = 32,
assign write_enable = mem_write_enable;
// debug output ------------------------------------------------------------------------------------
- assign led1 = reset;
- assign led2 = ins_loadc;
- assign led3 = ins_branch;
-// assign debug_out1 = { mem_read_enable, mem_write_enable, x_is_zero,
-// ins_branch, ins_aluop, y_lessthan_x, x_equals_y, {7{1'b0}}, seq_state};
-// assign debug_out2 = data_in;
-// assign debug_out3 = nX;
-// assign debug_out4 = nPC;
-// assign debug_out5 = ins;
-// assign debug_out6 = IV;
+ assign debug1 = reset;
+ assign debug2 = ins_loadc;
+ assign debug3 = ins_branch;
+
//--------------------------------------------------------------------------------------------------
// instruction decoding
diff --git a/tridoracpu/tridoracpu.srcs/tdraudio.v b/tridoracpu/tridoracpu.srcs/tdraudio.v
index 0cc055e..1629e31 100644
--- a/tridoracpu/tridoracpu.srcs/tdraudio.v
+++ b/tridoracpu/tridoracpu.srcs/tdraudio.v
@@ -7,7 +7,7 @@ module wavegen #(DATA_WIDTH=32, CLOCK_DIV_WIDTH=22,
input wire reset,
input wire [1:0] reg_sel,
output wire [DATA_WIDTH-1:0] rd_data,
- input wire [DATA_WIDTH-1:0] wr_data,
+ input wire [AMP_WIDTH-1:0] wr_data,
input wire rd_en,
input wire wr_en,
@@ -20,6 +20,9 @@ module wavegen #(DATA_WIDTH=32, CLOCK_DIV_WIDTH=22,
localparam TDRAU_REG_CLK = 1; /* clock divider register */
localparam TDRAU_REG_AMP = 2; /* amplitude (volume) register */
+ /* avoid warning about unconnected port */
+ (* keep="soft" *) wire _unused = rd_en;
+
reg channel_enable;
reg [CLOCK_DIV_WIDTH-1:0] clock_div;
reg [CLOCK_DIV_WIDTH-1:0] div_count;
@@ -29,12 +32,12 @@ module wavegen #(DATA_WIDTH=32, CLOCK_DIV_WIDTH=22,
wire fifo_wr_en;
wire fifo_rd_en, fifo_full, fifo_empty;
- wire [DATA_WIDTH-1:0] fifo_rd_data;
+ wire [AMP_WIDTH-1:0] fifo_rd_data;
fifo #(.ADDR_WIDTH(4), .DATA_WIDTH(16)) sample_buf(
clk, reset,
fifo_wr_en, fifo_rd_en,
- wr_data, fifo_rd_data,
+ wr_data[AMP_WIDTH-1:0], fifo_rd_data,
fifo_full,
fifo_empty
);
@@ -166,9 +169,14 @@ module tdraudio #(DATA_WIDTH=32) (
localparam AMP_BIAS = 32768;
localparam DAC_WIDTH = 18;
+ /* avoid warning about unconnected port */
+ (* keep="soft" *) wire [DATA_WIDTH-1:AMP_WIDTH] _unused = wr_data[DATA_WIDTH-1:AMP_WIDTH];
+
wire [4:0] chan_sel = io_addr[6:2];
wire [1:0] reg_sel = io_addr[1:0];
+ wire [AMP_WIDTH-1:0] amp_wr_data = wr_data[AMP_WIDTH-1:0];
+
wire [AMP_WIDTH-1:0] chan0_amp;
wire [DATA_WIDTH-1:0] chan0_rd_data;
wire chan0_running;
@@ -210,25 +218,25 @@ module tdraudio #(DATA_WIDTH=32) (
{DATA_WIDTH{1'b1}};
wavegen chan0(clk, reset, reg_sel,
- chan0_rd_data, wr_data,
+ chan0_rd_data, amp_wr_data,
chan0_rd_en, chan0_wr_en,
chan0_amp,
chan0_running, chan0_irq);
wavegen chan1(clk, reset, reg_sel,
- chan1_rd_data, wr_data,
+ chan1_rd_data, amp_wr_data,
chan1_rd_en, chan1_wr_en,
chan1_amp,
chan1_running, chan1_irq);
wavegen chan2(clk, reset, reg_sel,
- chan2_rd_data, wr_data,
+ chan2_rd_data, amp_wr_data,
chan2_rd_en, chan2_wr_en,
chan2_amp,
chan2_irq, chan2_running);
wavegen chan3(clk, reset, reg_sel,
- chan3_rd_data, wr_data,
+ chan3_rd_data, amp_wr_data,
chan3_rd_en, chan3_wr_en,
chan3_amp,
chan3_running, chan3_irq);
diff --git a/tridoracpu/tridoracpu.srcs/top.v b/tridoracpu/tridoracpu.srcs/top.v
index 6a70ef0..a4533d2 100644
--- a/tridoracpu/tridoracpu.srcs/top.v
+++ b/tridoracpu/tridoracpu.srcs/top.v
@@ -15,9 +15,6 @@
module top(
input wire clk,
input wire rst,
- input wire btn0,
- input wire sw0,
- input wire sw1,
output wire led0,
output wire led1,
output wire led2,
@@ -229,6 +226,15 @@ module top(
assign uart_rd_data = { {WIDTH-10{1'b1}}, uart_rx_avail, uart_tx_busy, uart_rx_data };
wire audio_irq;
+
+ buart #(.CLKFREQ(`clkfreq)) uart0(`clock, rst,
+ uart_baud,
+ uart_txd_in, uart_rxd_out,
+ uart_rx_clear, uart_tx_en,
+ uart_rx_avail, uart_tx_busy,
+ uart_tx_data, uart_rx_data);
+
+ // audio controller
`ifdef ENABLE_TDRAUDIO
wire [WIDTH-1:0] tdraudio_wr_data;
wire [WIDTH-1:0] tdraudio_rd_data;
@@ -273,13 +279,6 @@ module top(
`endif
-1;
- buart #(.CLKFREQ(`clkfreq)) uart0(`clock, rst,
- uart_baud,
- uart_txd_in, uart_rxd_out,
- uart_rx_clear, uart_tx_en,
- uart_rx_avail, uart_tx_busy,
- uart_tx_data, uart_rx_data);
-
// CPU -----------------------------------------------------------------
stackcpu cpu0(.clk(`clock), .rst(rst), .irq(irq),
.addr(mem_addr),
@@ -287,7 +286,7 @@ module top(
.read_ins(dram_read_ins),
.data_out(mem_write_data), .write_enable(mem_write_enable),
.mem_wait(mem_wait),
- .led1(led1), .led2(led2), .led3(led3));
+ .debug1(led1), .debug2(led2), .debug3(led3));
// Interrupt Controller
irqctrl irqctrl0(`clock, irq_in, irqc_cs, mem_write_enable,
diff --git a/tridoracpu/tridoracpu.xpr b/tridoracpu/tridoracpu.xpr
index 3767063..a9dc20f 100644
--- a/tridoracpu/tridoracpu.xpr
+++ b/tridoracpu/tridoracpu.xpr
@@ -378,30 +378,19 @@
-
+
-
- Similar to Performance_ExplorePostRoutePhysOpt, but enables logic optimization step (opt_design) with the ExploreWithRemap directive.
+
+ Default settings for Implementation.
-
-
-
+
-
-
-
+
-
-
-
-
-
-
-
-
-
-
+
+
+
diff --git a/utils/serload.py b/utils/serload.py
index 6ccc4a6..e69837f 100644
--- a/utils/serload.py
+++ b/utils/serload.py
@@ -16,6 +16,7 @@
# limitations under the License.
import sys
+import os
import serial
import time
import random
@@ -41,30 +42,6 @@ def get_default_device():
return '/dev/ttyUSB1'
-def serwrite_slow(databytes, ser):
- total = len(data)
- count = 1
- for d in data:
- sys.stdout.write("writing {0:02x} {1:04d}/{2:04d}\r".format(ord(d), count, total))
- ser.write(bytes(d,"utf8"))
- count += 1
- time.sleep(0.020)
- print()
-
-
-def serwrite(datafile, ser):
- with open(datafile) as f:
- data = f.read()
- total = len(data)
- count = 1
- for d in data:
- sys.stdout.write("writing {0:02x} {1:04d}/{2:04d}\r".format(ord(d), count, total))
- ser.write(bytes(d,"utf8"))
- count += 1
- time.sleep(0.020)
- print()
-
-
def checksum(databytes):
i = 0
cksum = 0
@@ -85,10 +62,26 @@ def sendchar(char, ser):
ser.write(char.to_bytes(1, 'big'))
-def sendcommand(ser, cmd=b'L'):
+def sendcommand(ser, cmd=b'L', verbose=False):
+ verbose = True
ser.write(cmd)
resp = ser.read_until()
- print(cmd,"sent, response:", str(resp))
+ if verbose:
+ print(cmd,"sent, response:", str(resp))
+ return resp
+
+
+# send command and wait for echo
+def commandwait(ser, cmd):
+ resp = sendcommand(ser, cmd, verbose=False)
+ if len(resp) == 0:
+ print("timeout sending '{}' command".format(cmd))
+ return None
+
+ if resp != bytearray(cmd + b"\r\n"):
+ print("invalid response to '{}' command".format(cmd))
+ return None
+
return resp
@@ -153,6 +146,8 @@ def serload_bin(datafile, ser):
data += bytearray(pad)
+ print("{} total blocks".format((len(data) + blocksize - 1) // blocksize))
+
if not send_size_header(ser, filesize):
print("Error sending size header.")
return
@@ -279,18 +274,8 @@ def serdownload(fname, ser):
def mput(filenames, ser):
for f in filenames:
- f_encoded = f.encode('utf8')
- print("Setting filename", f)
- resp = sendcommand(ser, b'S')
- if len(resp) == 0:
- print("timeout sending 'S' command")
- return
- if resp != b'S\r\n' and resp != b'> S\r\n':
- print("unrecognized response to 'S' command, aborting")
- return
- resp = sendcommand(ser, f_encoded + b'\r')
- if not f_encoded in resp:
- print("unrecognized response to filename, aborting")
+ resp = set_filename(f, ser)
+ if resp is None:
return
serload_bin(f, ser)
@@ -299,12 +284,92 @@ def mput(filenames, ser):
time.sleep(2)
+def set_filename(f, ser):
+ f_encoded = f.encode('utf8')
+ print("Setting filename", f)
+ resp = commandwait(ser, b'S')
+ if resp is None:
+ return None
+ resp = sendcommand(ser, f_encoded + b'\r')
+ if not f_encoded in resp:
+ print("unrecognized response to filename, aborting")
+ return None
+ return resp
+
+
+def getnamedfile(filename, ser):
+ resp = set_filename(filename, ser)
+ if resp is None:
+ return None
+ serdownload(filename, ser)
+
+
+def putnamedfile(filename, ser):
+ resp = set_filename(filename, ser)
+ if resp is None:
+ return None
+ serload_bin(filename, ser)
+ print("Remote status:")
+ showdata(ser)
+
+
+def showdata(ser):
+
+ promptseen = False
+
+ while not promptseen:
+ c = ser.read(1)
+ if c == b'>':
+ promptseen = True
+ else:
+ print(c.decode('utf8'), end='')
+ rest = ser.read(1)
+
+
+def localdir():
+ result = os.walk(".")
+ for dirpath, dirnames, filenames in os.walk("."):
+ for f in filenames:
+ print(f)
+ break
+
+
+def interactive(ser):
+ done = False
+ while not done:
+ args = input("> ").strip().split()
+ if len(args) > 0:
+ cmd = args[0]
+ args.pop(0)
+ if cmd == 'dir':
+ if commandwait(ser, b'Y') is None:
+ return
+ showdata(ser)
+ elif cmd == 'get':
+ if len(args) > 1:
+ print("exactly one argument required (filename)")
+ else:
+ getnamedfile(args[0], ser)
+ elif cmd == 'put':
+ if len(args) > 1:
+ print("exactly one argument required (filename)")
+ else:
+ putnamedfile(args[0], ser)
+ elif cmd == 'ldir':
+ if len(args) > 0:
+ print("superfluous argument")
+ else:
+ localdir()
+ else:
+ print("Unknown command. Valid commands are: dir get ldir put")
+
+
if __name__ == "__main__":
argparser = argparse.ArgumentParser(
description='transfer files from/to the Tridora-CPU')
argparser.add_argument('-d', '--device', help='serial device', default=get_default_device())
- argparser.add_argument('command', choices=['get', 'put', 'mput'])
- argparser.add_argument('filename', nargs='+')
+ argparser.add_argument('command', choices=['get', 'put', 'mput', 'interactive'])
+ argparser.add_argument('filename', nargs='*')
args = argparser.parse_args()
cmd = args.command
@@ -319,8 +384,10 @@ if __name__ == "__main__":
serload_bin(filenames[0], ser)
elif cmd == 'mput':
mput(filenames, ser)
+ elif cmd == 'interactive':
+ interactive(ser)
else:
print("should not get here")
- if cmd is not None:
- ser.close()
+ #if cmd is not None:
+ # ser.close()