Skip to content

Commit

Permalink
Implement a basic IO driver, allowing the CPU to read the switches an…
Browse files Browse the repository at this point in the history
…d buttons, control the LEDs, and output to the SSD in hex, decimal, characters or individual bits (segments). A basic font up to the letter 'v' is hardwired (tables of more than 32 entries don't get mapped to MUXs very well).
  • Loading branch information
ejrh committed Dec 15, 2014
1 parent 7869662 commit 81c4e4c
Show file tree
Hide file tree
Showing 11 changed files with 181 additions and 76 deletions.
3 changes: 2 additions & 1 deletion programs/fibonacci.asm
Expand Up @@ -3,7 +3,8 @@ fibonacci::
mov 10000, $r3
mov 0, $r1
mov 1, $r2
start: out $r2, 1
mov 16, $r6
start: out $r2, $r6, 2
slt $r3, $r2, $r4
br $r4, stop
add $r1, $r2, $r5
Expand Down
3 changes: 2 additions & 1 deletion programs/primes.asm
Expand Up @@ -5,8 +5,9 @@ primes::
mov 0, $r4 ; Start of primes array
mov 0, $r5 ; End of primes array (exclusive)
mov 2, $r2 ; First prime
mov 16, $r10

found_prime: out $r2, 1 ; Print
found_prime: out $r2, $r10, 2 ; Print
store $r2, $r5, 0 ; Append to array
add $r1, $r5, $r5
Expand Down
5 changes: 3 additions & 2 deletions programs/simple_mem.asm
Expand Up @@ -2,10 +2,11 @@
simple_mem::
mov 1, $r4
mov 10, $r3 ; Test first 10 words
mov 16, $r10

mov 0, $r1
store_loop:
out $r1, 1
out $r1, $r10, 2
store $r1, $r1, 0 ; Store $r1 into mem[$r1]
add $r1, $r4, $r1
slt $r1, $r3, $r2
Expand All @@ -14,7 +15,7 @@ store_loop:
mov 0, $r1
load_loop:
load $r1, 0, $r5 ; Load $r5 from mem[$r1]
out $r5, 1
out $r5, $r10, 2
add $r1, $r4, $r1
slt $r1, $r3, $r2
br $r2, load_loop ; If $r1 < $r3, keep going
Expand Down
3 changes: 2 additions & 1 deletion programs/slowprimes.asm
Expand Up @@ -3,6 +3,7 @@ primes::
mov 1, $r1 ; Increment value
mov 10000, $r3 ; Maximum number to search up to
mov 1, $r2 ; Number just before first candidate to check
mov 16, $r10 ; Offset of IO ports

new_candidate: add $r1, $r2, $r2
slt $r3, $r2, $r6 ; Check if reached maximum number
Expand All @@ -25,7 +26,7 @@ next_divisor: add $r1, $r8, $r8 ; Next divisor
slt $r8, $r2, $r6
br $r6, check_divisor
out $r2, 1 ; Print
out $r2, $r10, 2 ; Print
jmp new_candidate ; No divisors found

stop: out $r0, 0
Expand Down
18 changes: 9 additions & 9 deletions rtl/cpu.v
@@ -1,7 +1,7 @@
module cpu(clk,
ins_mem, ins_pointer, ins_read_enable,
memaddr, memval, memget, memset, memout,
portaddr, portval, portget, portset, portout,
port_read, port_write, port_addr, port_write_data, port_read_data,
bus_addr, bus_read, bus_write, bus_data,
state, opcode);

Expand Down Expand Up @@ -55,14 +55,14 @@ module cpu(clk,
assign aluin1 = regval1;
assign aluin2 = regval2;

output wire [WORD_SIZE-1:0] portaddr, portval;
output wire portget, portset;
input wire [WORD_SIZE-1:0] portout;
output wire [WORD_SIZE-1:0] port_addr, port_write_data;
output wire port_read, port_write;
input wire [WORD_SIZE-1:0] port_read_data;

assign portaddr = regval2 + smallval;
assign portval = regval1;
assign portget = do_memload & (opcode == `OP_IN);
assign portset = do_memstore & (opcode == `OP_OUT);
assign port_addr = regval2 + smallval;
assign port_write_data = regval1;
assign port_read = do_memload & (opcode == `OP_IN);
assign port_write = do_memstore & (opcode == `OP_OUT);

output wire [WORD_SIZE-1:0] memaddr, memval;
output wire memget, memset;
Expand All @@ -73,7 +73,7 @@ module cpu(clk,
assign memget = do_memload & (opcode == `OP_LOAD);
assign memset = do_memstore & (opcode == `OP_STORE);

assign storeval = (opcode == `OP_IN) ? portout
assign storeval = (opcode == `OP_IN) ? port_read_data
: (opcode == `OP_LOAD) ? memout
: (opcode == `OP_LOADLO) ? ((regval1 & 16'hFF00) | bigval)
: (opcode == `OP_LOADHI) ? ((regval1 & 16'h00FF) | (bigval << 8))
Expand Down
60 changes: 60 additions & 0 deletions rtl/io_driver.v
@@ -0,0 +1,60 @@
module io_driver(clk,
sw, btn, led,
ssd_bits, ssd_char_mode,
port_read, port_write, port_addr, port_write_data, port_read_data
);

`include "parameters.vh"

input wire clk;

input wire [3:0] btn;
input wire [7:0] sw;
output reg [3:0] led;
output reg [31:0] ssd_bits = 32'hFFFFFFFF;
output reg ssd_char_mode = 0;

input wire port_read;
input wire port_write;
input wire [15:0] port_addr;
input wire [15:0] port_write_data;
output reg [15:0] port_read_data;

/* LEDs */
always @(posedge clk) begin
if (port_write && port_addr == `PORT_IO_LED) begin
led <= port_write_data[3:0];
end
end

/* Seven segment display */
wire [15:0] bcd;
convert_to_bcd convert_to_bcd(port_write_data, bcd);

always @(posedge clk) begin
if (port_write && port_addr == `PORT_IO_HEX) begin
ssd_bits <= { 4'b0000, port_write_data[15:12], 4'b0000, port_write_data[11:8], 4'b0000, port_write_data[7:4], 4'b0000, port_write_data[3:0] };
ssd_char_mode <= 1;
end else if (port_write && port_addr == `PORT_IO_DEC) begin
ssd_bits <= { 4'b0000, bcd[15:12], 4'b0000, bcd[11:8], 4'b0000, bcd[7:4], 4'b0000, bcd[3:0] };
ssd_char_mode <= 1;
end else if (port_write && port_addr == `PORT_IO_CHAR) begin
ssd_bits <= { ssd_bits[15:0], port_write_data };
ssd_char_mode <= 1;
end else if (port_write && port_addr == `PORT_IO_BITS) begin
ssd_bits <= { ssd_bits[15:0], port_write_data };
ssd_char_mode <= 0;
end
end

/* Switches and buttons */
always @(posedge clk) begin
port_read_data <= 0;
if (port_read && port_addr == `PORT_IO_SWITCH) begin
port_read_data <= { 8'h00, sw };
end else if (port_read && port_addr == `PORT_IO_BUTTON) begin
port_read_data <= { 12'h00, btn };
end
end

endmodule
41 changes: 19 additions & 22 deletions rtl/machine.v
Expand Up @@ -32,12 +32,12 @@ module machine(
wire [INS_ADDR_SIZE-1:0] ins_pointer;
wire ins_read_enable;

wire [WORD_SIZE-1:0] portaddr, portval;
wire portget, portset;
wire [WORD_SIZE-1:0] portout;
wire [WORD_SIZE-1:0] port_addr, port_write_data;
wire port_read, port_write;
wire [WORD_SIZE-1:0] port_read_data;

wire [WORD_SIZE-1:0] memaddr, memval;
wire memget, memset;
wire memget, memset;
wire [WORD_SIZE-1:0] memout;

// 8-bit control bus
Expand All @@ -51,30 +51,27 @@ module machine(
cpu cpu(slowclk,
ins_mem, ins_pointer, ins_read_enable,
memaddr, memval, memget, memset, memout,
portaddr, portval, portget, portset, portout,
port_read, port_write, port_addr, port_write_data, port_read_data,
bus_addr, bus_read, bus_write, bus_data,
state, opcode);

data_memory data_mem(slowclk, memaddr, memval, memget, memset, memout);

reg [15:0] show_val;
wire show_sel;
ssd_driver ssd(mclk, (state == `STATE_INSMEM_LOAD) ? 9999 : show_val, an, seg, dp);

assign show_sel = sw[0];

always @(posedge slowclk) begin
if (portset) begin
//if (portaddr[0] == show_sel) begin
show_val <= portval;
// $display("Output %d on port %d", portval, portaddr);
//end
end
end
/* IO */
wire [31:0] ssd_bits;
wire ssd_char_mode;
wire [31:0] actual_ssd_bits = (state == `STATE_INSMEM_LOAD) ? { 8'h15, 8'h18, 8'h0A, 8'h0D } : ssd_bits;
wire actual_ssd_char_mode = (state == `STATE_INSMEM_LOAD) ? 1 : ssd_char_mode;

ssd_driver ssd(mclk,
an, seg, dp,
actual_ssd_bits, actual_ssd_char_mode
);

assign led[7:4] = opcode;
assign led[3:0] = state[3:0];
//assign led[0] = show_sel;
io_driver io(mclk,
sw, btn, led, ssd_bits, ssd_char_mode,
port_read, port_write, port_addr, port_write_data, port_read_data
);

//bus bus(bus_addr, bus_read, bus_write, bus_data);

Expand Down
8 changes: 8 additions & 0 deletions rtl/parameters.vh
Expand Up @@ -37,3 +37,11 @@ parameter REG_STACK_SIZE = 16;
`define CTRL_CPU_STATE 8'h00
`define CTRL_INSMEM_POS 8'h02
`define CTRL_INSMEM_DATA 8'h03

`define PORT_IO_LED 16'h0010
`define PORT_IO_HEX 16'h0011
`define PORT_IO_DEC 16'h0012
`define PORT_IO_CHAR 16'h0013
`define PORT_IO_BITS 16'h0014
`define PORT_IO_SWITCH 16'h0015
`define PORT_IO_BUTTON 16'h0016
94 changes: 63 additions & 31 deletions rtl/ssd_driver.v
Expand Up @@ -2,20 +2,20 @@

module ssd_driver(
input clk,
input [15:0] inval,

output reg [3:0] an,
output reg [6:0] seg,
output dp
);
output wire [6:0] seg,
output dp,

wire [15:0] val;
convert_to_bcd convert_to_bcd(inval, val);
input [31:0] ssd_bits,
input ssd_char_mode
);

//NOTE With the seven segment display, 1 indicates off...

assign dp = 1'b1; // Decimal point off

reg [3:0] sel = 4'b0000;
reg [5:0] sel = 4'b0000;

reg [15:0] cnt; //TODO no idea if 65k/50M = 1.31ms is the optimal cycle time (0.33ms per anode)
wire [1:0] dis;
Expand All @@ -25,50 +25,82 @@ module ssd_driver(
cnt <= cnt + 1;
end

always @(inval) begin
$display("ssd inval = %d", inval);
end
reg [6:0] bit_seg;
reg [6:0] char_seg;

assign seg = ssd_char_mode ? char_seg : bit_seg;

always @(*) begin
case (dis)
2'b00: begin
sel = val[3:0];
sel = ssd_bits[5:0];
an = 4'b1110;
bit_seg = ssd_bits[6:0];
end
2'b01: begin
sel = val[7:4];
sel = ssd_bits[13:8];
an = 4'b1101;
bit_seg = ssd_bits[14:8];
end
2'b10: begin
sel = val[11:8];
sel = ssd_bits[21:16];
an = 4'b1011;
bit_seg = ssd_bits[22:16];
end
2'b11: begin
sel = val[15:12];
sel = ssd_bits[29:24];
an = 4'b0111;
bit_seg = ssd_bits[30:24];
end
endcase
end

always @(*) begin
case (sel)
4'b0001: seg = 7'b1111001; // 1
4'b0010: seg = 7'b0100100; // 2
4'b0011: seg = 7'b0110000; // 3
4'b0100: seg = 7'b0011001; // 4
4'b0101: seg = 7'b0010010; // 5
4'b0110: seg = 7'b0000010; // 6
4'b0111: seg = 7'b1111000; // 7
4'b1000: seg = 7'b0000000; // 8
4'b1001: seg = 7'b0010000; // 9
4'b1010: seg = 7'b0001000; // A
4'b1011: seg = 7'b0000011; // b
4'b1100: seg = 7'b1000110; // C
4'b1101: seg = 7'b0100001; // d
4'b1110: seg = 7'b0000110; // E
4'b1111: seg = 7'b0001110; // F
default: seg = 7'b0111111; // -
endcase
6'h00: char_seg = 7'b1000000; // 0
6'h01: char_seg = 7'b1111001; // 1
6'h02: char_seg = 7'b0100100; // 2
6'h03: char_seg = 7'b0110000; // 3
6'h04: char_seg = 7'b0011001; // 4
6'h05: char_seg = 7'b0010010; // 5
6'h06: char_seg = 7'b0000010; // 6
6'h07: char_seg = 7'b1111000; // 7
6'h08: char_seg = 7'b0000000; // 8
6'h09: char_seg = 7'b0010000; // 9
6'h0A: char_seg = 7'b0001000; // A
6'h0B: char_seg = 7'b0000011; // b
6'h0C: char_seg = 7'b1000110; // C
6'h0D: char_seg = 7'b0100001; // d
6'h0E: char_seg = 7'b0000110; // E
6'h0F: char_seg = 7'b0001110; // F
6'h10: char_seg = 7'b0111000; // G
6'h11: char_seg = 7'b0001011; // h
6'h12: char_seg = 7'b0010000; // i
6'h13: char_seg = 7'b1110001; // J
6'h14: char_seg = 7'b0001101; // K
6'h15: char_seg = 7'b1000111; // L
6'h16: char_seg = 7'b1001000; // M
6'h17: char_seg = 7'b0101011; // n
6'h18: char_seg = 7'b0100011; // o
6'h19: char_seg = 7'b0001100; // P
6'h1A: char_seg = 7'b1000100; // Q
6'h1B: char_seg = 7'b0101111; // r
6'h1C: char_seg = 7'b1010010; // S
6'h1D: char_seg = 7'b1001110; // T
6'h1E: char_seg = 7'b1100011; // u
6'h1F: char_seg = 7'b1110011; // v
/*
6'h20: char_seg = 7'b1000001; // W
6'h21: char_seg = 7'b0110110; // X
6'h22: char_seg = 7'b0111011; // Y
6'h23: char_seg = 7'b1101100; // Z
6'h24: char_seg = 7'b1111110; // -
6'h25: char_seg = 7'b1111111; // .
6'h26: char_seg = 7'b1110111; // _
6'h27: char_seg = 7'b1111111; // SPACE
*/
default: char_seg = 7'b0110110; // -
endcase
end

endmodule

0 comments on commit 81c4e4c

Please sign in to comment.