entity MiniCounter { in clk: bit, in reset: bit, out ready: bit, in max: bit[16], } impl MiniCounter { def mut index: bit[16]; // total is a 16-bit value def index_next: bit[16] = index + 1; // def mut milli_tick: uint{..12000}; // one microsecond def mut micro_tick: uint{..12}; // one microsecond def micro_tick_next: uint{..12} = micro_tick + 1; const MICRO_MAX = 12; def max_cap: bit[16] = max - 1; on clk.posedge { if reset { ready <= 0; index <= 0; micro_tick <= 0; } else { if micro_tick == (MICRO_MAX - 1) { if index == max_cap { ready <= 1; } else { micro_tick <= 0; index <= index_next; } } else { micro_tick <= micro_tick_next; } } } } entity SpiMaster { in reset: bit, in clk: bit, in trigger: bit, out ready: bit, in tx_byte: bit[8], out rx_byte: bit[8], out spi_clk: bit, out spi_tx: bit, in spi_rx: bit, } impl SpiMaster { def mut live_clk: bit; // Internal signals. def mut read_index: uint{..9}; def read_index_next: uint{..9} = read_index - 1; def mut internal_clk: bit; def internal_clk_next: bit = !internal_clk; // Generate SPI signal from internal clock + SPI state. spi_clk = live_clk && internal_clk; // Generate divided SPI clock. def mut div_idx: uint{..40}; def div_idx_next: uint{..40} = div_idx + 1; on clk.negedge { if reset { div_idx <= 0; internal_clk <= 0; } else { if div_idx == (40 - 1) { internal_clk <= internal_clk_next; div_idx <= 0; } else { div_idx <= div_idx_next; } } } // Sample read values from positive clock edge. on internal_clk.posedge { if live_clk { rx_byte[read_index] <= spi_rx; } } def mut __FSM_1: bit[2]; def mut readier: bit; on clk.negedge { if reset { ready <= 0; } else { if __FSM_1 == 3 { ready <= readier; readier <= 0; } else { readier <= 1; } } } // SPI output state machine. on internal_clk.negedge { if !reset { fsm { INIT => { // Wait for transition trigger. spi_tx <= 0; if trigger { read_index <= 8; fsm <= WRITING; } } WRITING => { // Enable output clock. live_clk <= 1; // Write bits. if read_index != 0 { spi_tx <= tx_byte[read_index_next]; read_index <= read_index_next; } else { // Disable output clock. live_clk <= 0; fsm <= FINISH; } } FINISH => { fsm <= FINISH2; } FINISH2 => { fsm <= INIT; } } } } } // const WIDTH = 16; /// Stack. /// /// we | delta | action /// ------------------- /// 0 | ? 0 | n/a /// 0 | 0 1 | dup second into list /// 0 | 1 1 | pop, head <= popped item /// 1 | ? 0 | head <= wd /// 1 | 0 1 | push wd /// 1 | 1 1 | pop, head <= wd entity Stack2 { in clk: bit, out rd: bit[16], out rd2: bit[16], in we: bit, in delta: bit[3], in wd: bit[16], in sleeping: bit, } impl Stack2 { const WIDTH = 16; // TODO global const const DEPTH = 8; const BITS = WIDTH * DEPTH; // 0 = move 1, 1 = move 2 def move_2: bit = delta[2]; // 0 = push, 1 = pop def move_dir: bit = delta[1]; // Whether to push or pop def do_move: bit = delta[0]; def mut head: bit[16]; def mut tail: bit[128]; def headN: bit[16] = if we { wd } else { if move_2 { tail[32:16] } else { tail[16:0] } }; def tailN: bit[128] = if move_dir { if move_2 { {0x55aa, 0x55aa, tail[BITS:32]} } else { {0x55aa, tail[BITS:16]} } } else { {tail[BITS-16:0], head} }; on clk.posedge { if !sleeping { if we | do_move { head <= headN; } if do_move { tail <= tailN; } } } rd = head; rd2 = tail[16:0]; } entity J1a { in clk: bit, in reset: bit, // out mem_addr: bit[16], // out mem_wr: bit, // out dout: bit[WIDTH], out code_addr: bit[13], in insn: bit[16], out LED1: bit, out LED2: bit, out LED3: bit, out LED4: bit, out LED5: bit, out CS: bit, out SCK: bit, in MISO: bit, out MOSI: bit, out sleeping: bit, } impl J1a { const WIDTH = 16; // TODO global const const GOTO_INSN = 16b1000_0000_0000_0000 + 1; const IFZ_INSN = 16b1000_0000_0000_0000 + 7; const IFNZ_INSN = 16b1000_0000_0000_0000 + 8; const STORE_INSN = 16b1000_0000_0000_0000 + 10; const LED_INSN = 16b1100_0000_0000_0000 + 0; const SLEEP_INSN = 16b1100_0000_0000_0000 + 1; const TX_INSN = 16b1100_0000_0000_0000 + 2; const RX_INSN = 16b1100_0000_0000_0000 + 3; const CS_INSN = 16b1100_0000_0000_0000 + 4; // top of data stack def mut st0: bit[16]; def st0N: bit[16]; // data stack write def dstkW: bit; // program counter def mut pc: bit[13]; def pcN: bit[13]; def pc_plus_1: bit[13] = pc + 1b1; // TODO does above differ with wire [12:0] pc_plus_1 = pc + 13'd1 ? def mut reboot; // mem_addr = st0[16:0]; code_addr = pcN; // The D and R stacks def st1: bit[16]; def st2: bit[16]; def dspI: bit[3]; // stack2 #(.DEPTH(15)) dstack(.clk(clk), .rd(st1), .we(dstkW), .wd(st0), .delta(dspI)); def dstack = Stack2 { clk: clk, rd: st1, rd2: st2, we: dstkW, wd: st0, delta: dspI, sleeping: sleeping, }; def mut mem_set: bit[8][16]; def minus: bit[17] = {1b1, !st0} + st1 + 1; // def signedless: bit = if st0[15] ^ st1[15] { st1[15] } else { minus[16] }; // Compute the new value of st0 if insn[15] == 0 { // Literal st0N = insn; // {dstkW, dspI} = {1b1, 2b10}; dstkW = 1b1; dspI = 3b001; } else if insn[14] == 0 { match insn[14:0] { // Inverse 0 => { st0N = !minus[16:0]; // {dstkW, dspI} = {1b0, 2b00}; dstkW = 1b0; dspI = 3b000; }, // Goto 1 => { st0N = st1; // {dstkW, dspI} = {1b0, 2b11}; dstkW = 1b0; dspI = 3b011; }, // And 2 => { st0N = st0 & st1; // {dstkW, dspI} = {1b1, 2b11}; dstkW = 1b0; dspI = 3b011; }, // Or 3 => { st0N = st0 | st1; // {dstkW, dspI} = {1b1, 2b11}; dstkW = 1b0; dspI = 3b011; }, // Add 4 => { st0N = st0 + st1; // {dstkW, dspI} = {1b1, 2b11}; dstkW = 1b0; dspI = 3b011; }, // Sub 5 => { st0N = minus[16:0]; // {dstkW, dspI} = {1b1, 2b11}; dstkW = 1b0; dspI = 3b011; }, // Pop 6 => { st0N = st1; // {dstkW, dspI} = {1b0, 2b11}; dstkW = 1b0; dspI = 3b011; }, // ifz 7 => { st0N = st2; // {dstkW, dspI} = {1b0, 2b11}; dstkW = 1b0; dspI = 3b111; }, // ifnz 8 => { st0N = st2; // {dstkW, dspI} = {1b0, 2b11}; dstkW = 1b0; dspI = 3b111; }, // load 9 => { st0N = mem_set[st0]; // {dstkW, dspI} = {1b0, 2b11}; dstkW = 1b0; dspI = 3b000; }, // store 10 => { st0N = st2; // {dstkW, dspI} = {1b0, 2b11}; dstkW = 1b0; dspI = 3b111; }, // pop2 11 => { st0N = st2; // {dstkW, dspI} = {1b0, 2b11}; dstkW = 1b0; dspI = 3b111; }, _ => { st0N = {1; 16}; // {dstkW, dspI} = {1b0, 2b11}; dstkW = 1b0; dspI = 3b000; }, } } else { match insn[14:0] { // LED 0 => { st0N = st0; dstkW = 1b0; dspI = 3b011; }, // Sleepsville 1 => { st0N = st0; dstkW = 1b0; dspI = 3b011; }, // TX 2 => { st0N = st1; // {dstkW, dspI} = {1b0, 2b11}; dstkW = 1b0; dspI = 3b011; } // RX 3 => { // Literal st0N = spi_rx; // {dstkW, dspI} = {1b1, 2b10}; dstkW = 1b1; dspI = 3b001; } // CS 4 => { st0N = st0; // {dstkW, dspI} = {1b0, 2b00}; dstkW = 1b0; dspI = 3b000; } _ => { st0N = {1; 16}; // {dstkW, dspI} = {1b0, 2b11}; dstkW = 1b0; dspI = 3b000; }, } }; // 0b0_000_????? => st0N = st0; // jump // 0b0_010_????? => st0N = st0; // call // 0b0_001_????? => st0N = st1; // conditional jump // 0b0_011_?0000 => st0N = st0; // ALU operations... // 0b0_011_?0001 => st0N = st1; // 0b0_011_?0010 => st0N = st0 + st1; // 0b0_011_?0011 => st0N = st0 & st1; // 9'b0_011_?0100 => st0N = st0 | st1; // 9'b0_011_?0101 => st0N = st0 ^ st1; // 9'b0_011_?0110 => st0N = ~st0; // // 9'b0_011_?0111 => st0N = {`WIDTH{(minus == 0)}}; // = // 9'b0_011_?1000 => st0N = {`WIDTH{(signedless)}}; // < // // 9'b0_011_?1001 => st0N = {st0[`WIDTH - 1], st0[`WIDTH - 1:1]}; // 9'b0_011_?1010 => st0N = {st0[`WIDTH - 2:0], 1'b0}; // 9'b0_011_?1011 => st0N = rst0; // 9'b0_011_?1100 => st0N = minus[15:0]; // 9'b0_011_?1101 => st0N = io_din; // 9'b0_011_?1110 => st0N = {{(`WIDTH - 4){1'b0}}, dsp}; // 9'b0_011_?1111 => st0N = {`WIDTH{(minus[16])}}; // u< // _ => st0N = {`WIDTH{1'bx}}; // } // LED status on clk.posedge { if !reset && (!sleeping) { if insn == LED_INSN { match st0 { 1 => { LED1 <= 1; }, 2 => { LED2 <= 1; }, 3 => { LED3 <= 1; } 5 => { LED5 <= 1; } } } } } // always { // is_alu = !pc[12] & (insn[16:13] == 0b011); // mem_wr = !reboot & is_alu & func_write; // dout = st1; // } // // Updates data state. // match {pc[12], insn[15:13]} { // 0b1_??? => // 0b0_1?? => {dstkW, dspI} = {1'b1, 2'b01}, // 0b0_001 => {dstkW, dspI} = {1'b0, 2'b11}, // 0b0_011 => {dstkW, dspI} = {func_T_N, {insn[1:0]}}, // _: => {dstkW, dspI} = {1'b0, 2'b00}, // } // Updates PC. if reboot { pcN = 0; } else { match insn { GOTO_INSN => pcN = st0, IFZ_INSN => pcN = if st1 == 0 { st0 } else { pc_plus_1 }, IFNZ_INSN => pcN = if st1 != 0 { st0 } else { pc_plus_1 }, _ => pcN = pc_plus_1, } }; def counter_ready; def mut counter_trigger; def mut counter_value: bit[16]; def counter = MiniCounter { clk: clk, reset: counter_trigger, ready: counter_ready, max: counter_value, }; // Sleeping sleeping = spi_trigger | (!counter_trigger); def mut spi_trigger; def spi_ready; def mut spi_tx: bit[8]; def spi_rx: bit[8]; def spi = SpiMaster { reset: reset, clk: clk, trigger: spi_trigger, ready: spi_ready, tx_byte: spi_tx, rx_byte: spi_rx, spi_clk: SCK, spi_tx: MOSI, spi_rx: MISO, }; on clk.negedge { if reset { counter_trigger <= 1; spi_trigger <= 0; CS <= 1; } else { if sleeping & (counter_ready | spi_ready) { counter_trigger <= 1; spi_trigger <= 0; } else if !sleeping { match insn { SLEEP_INSN => { counter_trigger <= 0; counter_value <= st0; } TX_INSN => { CS <= 0; spi_trigger <= 1; spi_tx <= st0; } RX_INSN => { CS <= 0; spi_trigger <= 1; spi_tx <= 0xff; } CS_INSN => { CS <= 1; counter_trigger <= 0; counter_value <= 30; } } } } } on clk.negedge { if !reset { if insn == STORE_INSN { mem_set[st0] <= st1; } } } on clk.posedge { if reset { reboot <= 1; // { pc, st0 } <= 0; pc <= 0; st0 <= 0; } else { reboot <= 0; if !sleeping { // { pc, st0 } <= { pcN, st0N }; pc <= pcN; st0 <= st0N; } } } } entity Main { in clk: bit, out LED1: bit, out LED2: bit, out LED3: bit, out LED4: bit, out LED5: bit, out PMOD1: bit, out PMOD2: bit, in PMOD3: bit, out PMOD4: bit, } impl Main { // Reset is active high. We declare it inverse of a temporary value which is initialized to 0. def mut init_active; def mut init_counter: bit[8]; def reset = !init_active; // This is our one-second initial delay. on clk.negedge { init_counter <= init_counter + 1; if init_counter == 10 { init_active <= 1; } } const BINARY_LEN = 160; def binary: bit[16][160] = { 16b1100_0000_0000_0100, 16b0000_0000_0010_0010, 16b1100_0000_0000_0010, 16b0000_0000_0001_0110, 16b1100_0000_0000_0010, 16b0000_0000_0011_0100, 16b1100_0000_0000_0010, 16b0000_0000_0001_0010, 16b1100_0000_0000_0010, 16b1100_0000_0000_0100, 16b0000_0000_0010_0000, 16b1100_0000_0000_0010, 16b0000_0000_0001_0110, 16b1100_0000_0000_0010, 16b1100_0000_0000_0011, 16b0000_0000_0011_0100, 16b1000_0000_0000_0101, 16b0000_0000_1001_1100, 16b1000_0000_0000_1000, 16b1100_0000_0000_0011, 16b0000_0000_0001_0010, 16b1000_0000_0000_0101, 16b0000_0000_1001_1100, 16b1000_0000_0000_1000, 16b0000_0000_0000_0001, 16b1100_0000_0000_0000, 16b1100_0000_0000_0100, 16b0000_0000_1100_1010, 16b1100_0000_0000_0010, 16b0000_0000_0001_1110, 16b1100_0000_0000_0001, 16b0000_0000_0010_0010, 16b1100_0000_0000_0010, 16b0000_0000_0110_1110, 16b1100_0000_0000_0010, 16b0000_0000_0000_0000, 16b1100_0000_0000_0010, 16b0000_0000_1100_1011, 16b1100_0000_0000_0010, 16b1100_0000_0000_0100, 16b0000_0000_0010_0010, 16b1100_0000_0000_0010, 16b0000_0000_0000_0100, 16b1100_0000_0000_0010, 16b0000_0000_0100_0000, 16b1100_0000_0000_0010, 16b0000_0000_0101_0011, 16b1100_0000_0000_0010, 16b1100_0000_0000_0100, 16b0000_0000_0010_0010, 16b1100_0000_0000_0010, 16b0000_0000_0100_1010, 16b1100_0000_0000_0010, 16b0000_0000_0100_0000, 16b1100_0000_0000_0010, 16b0000_0000_0101_0011, 16b1100_0000_0000_0010, 16b1100_0000_0000_0100, 16b0000_0000_0010_0010, 16b1100_0000_0000_0010, 16b0000_0000_0000_0110, 16b1100_0000_0000_0010, 16b0000_0000_1111_1110, 16b1100_0000_0000_0010, 16b0000_0000_0101_1111, 16b1100_0000_0000_0010, 16b1100_0000_0000_0100, 16b0000_0000_0010_0000, 16b1100_0000_0000_0010, 16b0000_0000_0110_0100, 16b1100_0000_0000_0010, 16b1100_0000_0000_0011, 16b0000_0000_0000_0010, 16b1000_0000_0000_1010, 16b1100_0000_0000_0011, 16b0000_0000_0000_0011, 16b1000_0000_0000_1010, 16b1100_0000_0000_0100, 16b0000_0000_0010_0000, 16b1100_0000_0000_0010, 16b0000_0000_0110_0010, 16b1100_0000_0000_0010, 16b1100_0000_0000_0011, 16b0000_0000_0000_0100, 16b1000_0000_0000_1010, 16b1100_0000_0000_0011, 16b0000_0000_0000_0101, 16b1000_0000_0000_1010, 16b1100_0000_0000_0100, 16b0000_0000_0010_0000, 16b1100_0000_0000_0010, 16b0000_0000_0110_0000, 16b1100_0000_0000_0010, 16b1100_0000_0000_0011, 16b0000_0000_0000_0110, 16b1000_0000_0000_1010, 16b1100_0000_0000_0011, 16b0000_0000_0000_0111, 16b1000_0000_0000_1010, 16b1100_0000_0000_0100, 16b0000_0000_1110_1000, 16b1100_0000_0000_0010, 16b0000_0000_0100_0000, 16b0000_0000_0000_0001, 16b1000_0000_0000_1010, 16b0000_0000_0101_0011, 16b0000_0000_0000_0000, 16b1000_0000_0000_1010, 16b1100_0000_0000_0100, 16b0000_0000_1110_1000, 16b1100_0000_0000_0010, 16b1100_0000_0000_0100, 16b0000_0000_0001_1010, 16b1100_0000_0000_0010, 16b1100_0000_0000_0011, 16b0000_0000_0110_1100, 16b1000_0000_0000_0111, 16b0000_0000_0000_0010, 16b1100_0000_0000_0000, 16b1100_0000_0000_0100, 16b0000_0000_0010_0010, 16b1100_0000_0000_0010, 16b0000_0000_1000_1010, 16b1100_0000_0000_0010, 16b0000_0000_0000_0001, 16b1000_0000_0000_1001, 16b1100_0000_0000_0010, 16b0000_0000_0000_0000, 16b1000_0000_0000_1001, 16b1100_0000_0000_0010, 16b1100_0000_0000_0100, 16b0000_0000_0010_1100, 16b1100_0000_0000_0010, 16b1100_0000_0000_0011, 16b0000_0000_0000_0001, 16b1000_0000_0000_1010, 16b1100_0000_0000_0011, 16b0000_0000_0000_0000, 16b1000_0000_0000_1010, 16b1100_0000_0000_0011, 16b0000_0000_0000_1000, 16b1000_0000_0000_1010, 16b1100_0000_0000_0011, 16b0000_0000_0000_1001, 16b1000_0000_0000_1010, 16b1100_0000_0000_0011, 16b0000_0000_1000_0000, 16b1000_0000_0000_0010, 16b0000_0000_1001_1000, 16b1000_0000_0000_0111, 16b0000_0000_0000_0011, 16b1100_0000_0000_0000, 16b1100_0000_0000_0011, 16b1000_0000_0000_0110, 16b0000_0000_0110_1100, 16b1000_0000_0000_0001, 16b0000_0000_0000_0101, 16b1100_0000_0000_0000, 16b0000_0000_0000_0000, 16b1000_0000_0000_0001, }; def mut insn: bit[16]; def code_addr: bit[13]; def sleeping; def j1 = J1a { clk: clk, reset: reset, code_addr: code_addr, insn: insn, LED1: LED1, LED2: LED2, LED3: LED3, LED4: LED4, LED5: LED5, CS: PMOD1, MOSI: PMOD2, MISO: PMOD3, SCK: PMOD4, sleeping: sleeping, }; def mut error: bit; on clk.posedge { if !code_addr >= 0 && code_addr < BINARY_LEN { if !sleeping { insn <= binary[code_addr]; } } else if code_addr >= BINARY_LEN { error <= 1; } } }