`include "hvsync_generator.v" `include "cpu6502.v" `include "font_cp437_8x8.v" /** Mango One A 6502 computer inspired by Steve Wozniak's Apple I design Memory map: $0000 $0FFF RAM $A000 $CFFF Expansion ROM $D010 $D013 6821 PIA (keyboard, terminal) $E000 $EFFF Integer BASIC $FF00 $FFFF Woz Monitor, CPU vectors $D010 Read ASCII character from keyboard. If high bit is set then a key has been pressed. $D011 Writing to this address clears the high bit of $D010. The CPU usually does this after reading a key. $D012 Writes a character to the terminal. On read, if high bit is set then the display is not ready to receive characters. MangoMon commands: R aaaa - dump memory at $aaaa Enter - dump next 8 bytes W aaaa bb - write memory $bb at $aaaa G aaaa - jump to address $aaaa https://www.applefritter.com/replica/chapter7 https://github.com/mamedev/mame/blob/master/src/mame/drivers/apple1.cpp https://github.com/jefftranter/6502/blob/master/asm/wozmon/wozmon.s https://www.applefritter.com/files/signetics2513.pdf http://retro.hansotten.nl/uploads/6502docs/signetics2504.pdf http://retro.hansotten.nl/uploads/6502docs/signetics2519.pdf */ module signetics_term(clk, reset, hpos, vpos, tready, dot, te, ti); input clk,reset; input [8:0] hpos; input [8:0] vpos; input te; // input enable input [7:0] ti; // input data output tready; // terminal ready output dot; // terminal video output reg [7:0] dshift[1024]; // frame buffer offset reg [9:0] dofs; // current offset to write reg [9:0] scroll; // scroll offset reg [9:0] scnt; // row clear counter when scrolling always @(posedge clk or posedge reset) if (reset) begin scnt <= 0; scroll <= 0; dofs <= 28*32; scroll <= 0; end else if (scnt > 0) begin dshift[scroll] <= 0; // clear row when scrolling scroll <= scroll + 1; scnt <= scnt - 1; end else if (te) begin if (ti == 13) begin // CR, next row scnt <= 32; dofs <= ((dofs + 32) & ~31); end else if (ti >= 32) begin // display char dshift[dofs] <= ti; if ((dofs & 31) == 31) scnt <= 32; // wrap around dofs <= dofs + 1; end end // character generator from ROM font_cp437_8x8 tile_rom( .addr(char_addr), .data(char_data) ); wire [9:0] nt_addr = {vpos[7:3], hpos[7:3]}; wire [7:0] cur_char = dshift[nt_addr + scroll]; wire [10:0] char_addr = {cur_char, vpos[2:0]}; wire [7:0] char_data; wire dot = char_data[~hpos[2:0]]; // video output // terminal ready output // only possible at end of line, if not scrolling assign tready = !reset && !te && scnt == 0 && hpos == 256; initial begin integer i; for (i=0; i<1024; i=i+1) dshift[i] = 0; // clear buffer end endmodule module apple1_top(clk, reset, hsync, vsync, rgb, keycode, keystrobe); input clk, reset; input [7:0] keycode; output reg keystrobe; output hsync, vsync; output [2:0] rgb; wire display_on; wire [8:0] hpos; wire [8:0] vpos; wire [15:0] AB; // address bus wire [7:0] DI; // data in, read bus wire [7:0] DO; // data out, write bus wire WE; // write enable wire IRQ=0; // interrupt request wire NMI=0; // non-maskable interrupt request wire RDY=1; // Ready signal. Pauses CPU when RDY=0 cpu6502 cpu( clk, reset, AB, DI, DO, WE, IRQ, NMI, RDY ); always @(posedge clk) begin casez (AB) 16'h0zzz: DI <= ram[AB[11:0]]; 16'hd010: begin if (keycode >= 97+128 && keycode <= 122+128) DI <= keycode - 32; // convert to uppercase else DI <= keycode; // keyboard data keystrobe <= (keycode & 8'h80) != 0; // clear kbd buffer end 16'hd011: begin DI <= keycode & 8'h80; // keyboard status keystrobe <= 0; end 16'hd012: begin DI <= {!tready, 7'b0}; // display status end 16'hffzz: DI <= monitor_rom[AB[7:0]]; endcase end always @(posedge clk) if (WE) begin casez (AB) 16'hd010: begin end // 16'hd011: begin end // 16'hd012: begin end // handled by terminal module 16'hd013: begin end // 16'h0zzz: ram[AB[11:0]] <= DO; // write RAM endcase end reg [7:0] ram[4096]; // 1K of RAM reg [7:0] monitor_rom[256]; // WozMon ROM initial begin $readmemh("mango1.hex", monitor_rom); end hvsync_generator hvsync_gen( .clk(clk), .reset(reset), .hsync(hsync), .vsync(vsync), .display_on(display_on), .hpos(hpos), .vpos(vpos) ); wire tready; // terminal ready wire dot; // dot output wire te = WE && AB == 16'hd012; // terminal enable (write) signetics_term terminal(clk, reset, hpos, vpos, tready, dot, te, .ti(DO & 8'h7f)); wire r = display_on && 0; wire g = display_on && dot; wire b = display_on && 0; assign rgb = {b,g,r}; endmodule