diff options
Diffstat (limited to 'hdl/top.sv')
| -rw-r--r-- | hdl/top.sv | 89 |
1 files changed, 80 insertions, 9 deletions
| @@ -13,8 +13,28 @@ bit have_reset = 0; | |||
| 13 | always_ff @(posedge clk) if (reset) have_reset <= 1; | 13 | always_ff @(posedge clk) if (reset) have_reset <= 1; |
| 14 | assign reset = !reset_n || !have_reset; | 14 | assign reset = !reset_n || !have_reset; |
| 15 | 15 | ||
| 16 | bit [DATA_BITS-1:0] mem [0:(1<<ADDR_BITS)-1]; | 16 | bit mem_ready; `define mem_ready `past(mem_ready) |
| 17 | initial $readmemh("mem/mem.hex", mem); | 17 | bit mem_valid; |
| 18 | bit mem_write; | ||
| 19 | bit [ADDR_BITS-1:0] mem_address; | ||
| 20 | bit [DATA_BITS-1:0] mem_write_data; | ||
| 21 | bit [DATA_BITS-1:0] mem_read_data; | ||
| 22 | |||
| 23 | mem | ||
| 24 | #( .ADDR_BITS(ADDR_BITS) | ||
| 25 | , .DATA_BITS(DATA_BITS) | ||
| 26 | , .INIT_FILE("mem/mem.hex") | ||
| 27 | ) | ||
| 28 | memory | ||
| 29 | ( .clk(clk) | ||
| 30 | |||
| 31 | , .ready(mem_ready) | ||
| 32 | , .valid(mem_valid) | ||
| 33 | , .address(mem_address) | ||
| 34 | , .write(mem_write) | ||
| 35 | , .write_data(mem_write_data) | ||
| 36 | , .read_data(mem_read_data) | ||
| 37 | ); | ||
| 18 | 38 | ||
| 19 | bit rx_ready; | 39 | bit rx_ready; |
| 20 | bit rx_valid; | 40 | bit rx_valid; |
| @@ -48,10 +68,12 @@ bit [DATA_BITS-1:0] idx; | |||
| 48 | enum | 68 | enum |
| 49 | { FETCH | 69 | { FETCH |
| 50 | , DECODE | 70 | , DECODE |
| 71 | , MEMORY | ||
| 51 | } state; | 72 | } state; |
| 52 | 73 | ||
| 53 | always_ff @(posedge clk) begin | 74 | always_ff @(posedge clk) begin |
| 54 | if (reset) begin | 75 | if (reset) begin |
| 76 | mem_valid = 0; | ||
| 55 | rx_ready = 0; | 77 | rx_ready = 0; |
| 56 | tx_valid = 0; | 78 | tx_valid = 0; |
| 57 | tx_data = 0; | 79 | tx_data = 0; |
| @@ -60,22 +82,41 @@ always_ff @(posedge clk) begin | |||
| 60 | idx = 0; | 82 | idx = 0; |
| 61 | state = state.first; | 83 | state = state.first; |
| 62 | end else begin | 84 | end else begin |
| 85 | `ifdef DEBUG $display("s=%0d pc=%x (acc=%x idx=%x)", state, pc, acc, idx); `endif | ||
| 63 | if (`tx_ready) tx_valid = 0; | 86 | if (`tx_ready) tx_valid = 0; |
| 64 | 87 | ||
| 65 | case (state) | 88 | case (state) |
| 66 | FETCH: begin | 89 | FETCH: begin |
| 67 | {opcode, operand} = mem[{2'b0, pc}]; | 90 | `ifdef DEBUG $display("\tfetch"); `endif |
| 68 | ++pc; | 91 | mem_valid = 1; |
| 69 | state = DECODE; | 92 | mem_address = {2'b0, pc}; |
| 93 | mem_write = 0; | ||
| 94 | if (`mem_ready) begin | ||
| 95 | state = DECODE; | ||
| 96 | ++pc; | ||
| 97 | end | ||
| 70 | end | 98 | end |
| 71 | 99 | ||
| 72 | DECODE: begin | 100 | DECODE: begin |
| 73 | //$display("%x %x:%x (acc=%x idx=%x)", pc, opcode, operand, acc, idx); | 101 | mem_valid = 0; |
| 102 | mem_write = 0; | ||
| 74 | state = FETCH; | 103 | state = FETCH; |
| 104 | {opcode, operand} = mem_read_data; | ||
| 105 | `ifdef DEBUG $display("\tdecode %x:%x", opcode, operand); `endif | ||
| 75 | case (opcode) | 106 | case (opcode) |
| 76 | 'h0: acc = {{4{operand[7]}}, operand}; | 107 | 'h0: acc = {{4{operand[7]}}, operand}; |
| 77 | 'h1: acc = mem[idx + operand]; | 108 | 'h1: begin |
| 78 | 'h2: mem[idx + operand] = acc; | 109 | mem_valid = 1; |
| 110 | mem_address = idx + operand; | ||
| 111 | state = MEMORY; | ||
| 112 | end | ||
| 113 | 'h2: begin | ||
| 114 | mem_valid = 1; | ||
| 115 | mem_address = idx + operand; | ||
| 116 | mem_write = 1; | ||
| 117 | mem_write_data = acc; | ||
| 118 | if (! `mem_ready) state = MEMORY; | ||
| 119 | end | ||
| 79 | 'h3: if (acc != operand) ++pc; | 120 | 'h3: if (acc != operand) ++pc; |
| 80 | 'h4: pc = pc + {{4{operand[7]}}, operand}; | 121 | 'h4: pc = pc + {{4{operand[7]}}, operand}; |
| 81 | 'hf: begin | 122 | 'hf: begin |
| @@ -87,7 +128,7 @@ always_ff @(posedge clk) begin | |||
| 87 | if (operand[5]) idx = acc; | 128 | if (operand[5]) idx = acc; |
| 88 | if (operand[6]) begin | 129 | if (operand[6]) begin |
| 89 | if (tx_valid) begin | 130 | if (tx_valid) begin |
| 90 | state = DECODE; | 131 | state = MEMORY; |
| 91 | end else begin | 132 | end else begin |
| 92 | tx_valid = 1; | 133 | tx_valid = 1; |
| 93 | tx_data = acc[7:0]; | 134 | tx_data = acc[7:0]; |
| @@ -97,7 +138,37 @@ always_ff @(posedge clk) begin | |||
| 97 | end | 138 | end |
| 98 | endcase | 139 | endcase |
| 99 | end | 140 | end |
| 141 | |||
| 142 | MEMORY: begin | ||
| 143 | `ifdef DEBUG $display("\tstall"); `endif | ||
| 144 | if (`mem_ready) begin | ||
| 145 | mem_valid = 0; | ||
| 146 | mem_write = 0; | ||
| 147 | end | ||
| 148 | state = FETCH; | ||
| 149 | case (opcode) | ||
| 150 | 'h1: begin | ||
| 151 | if (`mem_ready) begin | ||
| 152 | acc = mem_read_data; | ||
| 153 | end else begin | ||
| 154 | state = MEMORY; | ||
| 155 | end | ||
| 156 | end | ||
| 157 | 'hf: begin | ||
| 158 | if (operand[6]) begin | ||
| 159 | if (tx_valid) begin | ||
| 160 | state = MEMORY; | ||
| 161 | end else begin | ||
| 162 | tx_valid = 1; | ||
| 163 | tx_data = acc[7:0]; | ||
| 164 | end | ||
| 165 | end | ||
| 166 | end | ||
| 167 | endcase | ||
| 168 | end | ||
| 100 | endcase | 169 | endcase |
| 170 | |||
| 171 | `ifdef DEBUG if (mem_valid) $display("\tmem addr=%x w=%b", mem_address, mem_write); `endif | ||
| 101 | end | 172 | end |
| 102 | end | 173 | end |
| 103 | 174 | ||
