src added not working or anything

This commit is contained in:
mrbesen 2020-02-04 16:35:48 +01:00
parent 8b05b7b07b
commit e1227820dd
Signed by: MrBesen
GPG Key ID: 596B2350DCD67504
8 changed files with 305 additions and 2 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
work/

View File

@ -1,3 +1,18 @@
# TIS-100-FPGA
# TIS-100 in Lucid for FPGA
A try to implement TIS 100 on a FPGA
I tried to implement [TIS-100](http://www.zachtronics.com/tis-100/) on a FPGA. I used the [Mojo-v3](https://alchitry.com/products/mojo-v3) from alchitry.
You need a tool (i am going to create one soon) to send a savefile from you computer to the programed FPGA.
Things currently not supported:
* ANY register - would just act like the NIL register
* graphical Output - nowhere to output too
* Stackstorage Nodes - comimg later
* debugging in any way
* speed control (step, fast run)
Keep in mind, that this is just a small Project to play around with a FPGA. I am pretty new to Lucid (the Language used) and i probably made every mistake - and bug - possible. So there is no warranty at all! But if you find something feel free to send me a message at `y.g.2 (at) gmx (dot) de`
###### Licence
This Project is Licenced under AGPLv3 a copy of the Licence should be alongside with the code.

33
source/mojo_top.luc Normal file
View File

@ -0,0 +1,33 @@
module mojo_top (
input clk, // 50MHz clock
input rst_n, // reset button (active low)
output led [8], // 8 user controllable LEDs
input cclk, // configuration clock, AVR ready when high
output spi_miso, // AVR SPI MISO
input spi_ss, // AVR SPI Slave Select
input spi_mosi, // AVR SPI MOSI
input spi_sck, // AVR SPI Clock
output spi_channel [4], // AVR general purpose pins (used by default to select ADC channel)
input avr_tx, // AVR TX (FPGA RX)
output avr_rx, // AVR RX (FPGA TX)
input avr_rx_busy // AVR RX buffer full
) {
sig rst; // reset signal
.clk(clk) {
// The reset conditioner is used to synchronize the reset signal to the FPGA
// clock. This ensures the entire FPGA comes out of reset at the same time.
reset_conditioner reset_cond;
}
always {
reset_cond.in = ~rst_n; // input raw inverted reset signal
rst = reset_cond.out; // conditioned reset
led = 8h00; // turn LEDs off
spi_miso = bz; // not using SPI
spi_channel = bzzzz; // not using flags
avr_rx = bz; // not using serial port
}
}

110
source/node.luc Normal file
View File

@ -0,0 +1,110 @@
global GNode {
const ROWS = 14; //number of commands to hold
const CMDLEN = 16; //number of bits a command is in size
const WORDLEN = 11; //bits to store a number (-999 to 999)
const REGISTERADDRLEN = 3; //bits to address a register
struct cmd {
cmd[4],
arg_is_const, //1 = argument is a 11bit signed integer, 0 argument is a register number
args[11] //11 bit number or at most 2 reigster (mov cmd)
}
}
/**
Register numbers:
0 = NIL
1 = ACC
2 = UP
3 = RIGHT
4 = DOWN
5 = LEFT
6 = LAST
7 = ANY
Subclk:
0 = Read cmd
1 = interpret cmd
2 = Mark input as read
3 = try to read
4 = mark output as read
5 = write to output
6 = increment pc and reset everything thats not needed anymore
cycles are skiped, if node is waiting for another node to read or write a connection
*/
module node (
input clk, // clock
input rst, // reset
input up_in[GNode.WORDLEN],
output<G_nodeCon.nodeConIn> up_out,
input right_in[GNode.WORDLEN],
output<G_nodeCon.nodeConIn> right_out,
input down_in[GNode.WORDLEN],
output<G_nodeCon.nodeConIn> down_out,
input left_in[GNode.WORDLEN],
output<G_nodeCon.nodeConIn> left_out,
output error,
input subclk
) {
.clk(clk), .rst(rst) {
dff pc[4](#INIT(0)); //program counter
dff<GNode.cmd> cmds[GNode.ROWS];
dff lastreg[3](#INIT(0)); // default = NIL
dff acc[GNode.WORDLEN](#INIT(0));
dff bak[GNode.WORDLEN](#INIT(0));
dff is_reading(#INIT(0));
dff is_writing(#INIT(0));
dff<GNode.cmd> currentCmd;
fsm currentCmdFSM = {MOV, // 2 args: 1const, 1reg or 2 reg
JEZ, JNZ, JGZ, JLZ, JRO, // 1 arg: 5bit(signed) const offset
ADD, SUB, // 1 arg: 1reg or 1 signed const
NEG, SWP, SAV}; // no arg
dff currentCmd_has_const(#INIT(0));
dff currentCmd_const[GNode.WORDLEN](#INIT(0));
dff currentCmd_has_reg[2](#INIT(0)); // only mov has two arguments (dst ist first; src ist second)
dff currentCmd_reg[2][3];//registers to use TODO: add #INIT(0)
registerMultiplex reg1(.selection(currentCmd_reg[0]), .acc(acc), .up(up), .right(right), .down(down), .left(left), .last(lastreg));
}
always {
error = 0;
if(subclk == 0 && is_reading.q == 0 && is_writing.q == 0) {
//read command
currentCmd.d = cmds.q[pc.q];
currentCmdFSM.d = cmds.q[pc.q];
} else if(subclk == 1 && is_reading.q == 0 && is_writing.q == 0) {
//interpret
//set them for all commands just set the _has_ flag if reguired
currentCmd_reg.d[0] = currentCmd.q.args[ GNode.REGISTERADDRLEN -1 : 0]; //3 LSB bytes = register 1
currentCmd_reg.d[1] = currentCmd.q.args[(2*GNode.REGISTERADDRLEN) -1 : GNode.REGISTERADDRLEN]; //3 next bytes = register 2
currentCmd_const.d = currentCmd.q.args;
//set the _has_ flags
currentCmd_has_const.d = (currentCmdFSM.q >= currentCmdFSM.JEZ && currentCmdFSM.q <= currentCmdFSM.JLZ) || currentCmd.q.arg_is_const == 1; //last bit of cmd indicates a constant for cmd's that can do both
currentCmd_has_reg.d[0] = (currentCmdFSM.q == currentCmdFSM.MOV || currentCmd.q.arg_is_const == 0); //mov cmd -> at least 1 reg or no constant
currentCmd_has_reg.d[1] = (currentCmdFSM.q == currentCmdFSM.MOV && currentCmd.q.arg_is_const == 0); //mov cmd und arg ist keine constante -> 2 register
} else if(subclk == 2 && is_reading.q == 0 && is_writing.q == 0) {
//mark input as read
is_reading.d = 1;
}
}

64
source/nodeCon.luc Normal file
View File

@ -0,0 +1,64 @@
/**
A Connection between two Nodes, blocks
*/
global G_nodeCon {
const WIDTH = 10;
struct nodeConIn {
write,
read,
enable,
in[WIDTH]
}
}
module nodeCon (
input clk, // clock
input rst, // reset
input<G_nodeCon.nodeConIn> a_in,
output a_out[G_nodeCon.WIDTH],
output done, //erledigt (blokirung kann uafgehoben werden)
/*input b_write,
input b_read,
input b_enable,
input b_in[WIDTH],*/
input<G_nodeCon.nodeConIn> b_in,
output b_out[G_nodeCon.WIDTH],
output error
) {
dff internalBuff[G_nodeCon.WIDTH](#INIT(0), .clk(clk), .rst(rst));
always {
error = ((a_in.write && b_in.write) || (a_in.read && b_in.read)) && ~rst && a_in.enable && b_in.enable; // gleichzeitiges lesen oder schreiben und nicht reset
done = (a_in.write && b_in.write) || (a_in.read && b_in.write) && a_in.enable && b_in.enable;
a_out = 0;
if(a_in.enable) {
if(a_in.write) {
internalBuff.d = a_in;
} else if(a_in.read) {
a_out = internalBuff.q;
}
}
b_out = 0;
if(b_in.enable) {
if(b_in.write) {
internalBuff.d = b_in;
} else if(b_in.read) {
b_out = internalBuff.q;
}
}
}
}

View File

@ -0,0 +1,58 @@
module registerMultiplex (
input clk, // clock
input rst, // reset
input selection[3], //which register? see node.luc for enumeration
input acc[GNode.WORDLEN],
input up[GNode.WORDLEN],
input right[GNode.WORDLEN],
input down[GNode.WORDLEN],
input left[GNode.WORDLEN],
input last[GNode.REGISTERADDRLEN], //CAREFULL! this is NOT a register! this is a address!
input any[GNode.WORDLEN],
output out[GNode.WORDLEN],
input in[GNode.WORDLEN],
input write,
input read
) {
dff outb[GNode.WORDLEN](.clk(clk), .rst(rst), #INIT(0));
always {
//reading
if(read) {
if(selection == 0) {
outb.d = 0;
} else if(selection == 1) {
outb.d = acc;
} else if(selection == 2) {
outb.d = up;
} else if(selection == 3) {
outb.d = right;
} else if(selection == 4) {
outb.d = down;
} else if(selection == 5) {
outb.d = left;
} else if(selection == 6) {
if(last == 0) { //inenr selection for last
}
} else if(selection == 7) {
outb.d = any;
} else {
outb.d = 0;
}
} else {
outb.d = 0;
}
out = outb.q;
if(write) {
//TODO: fwd in to the register and set writing flags
}
}
}

10
source/tis100.luc Normal file
View File

@ -0,0 +1,10 @@
module tis100 (
input clk, // clock
input rst, // reset
output out
) {
always {
out = 0;
}
}

12
tis-100.alp Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="tis-100" board="Mojo" language="Lucid" version="2">
<files>
<src>node.luc</src>
<src>tis100.luc</src>
<src top="true">mojo_top.luc</src>
<src>nodeCon.luc</src>
<src>registerMultiplex.luc</src>
<component>reset_conditioner.luc</component>
<constraint lib="true">mojo.ucf</constraint>
</files>
</project>