The idea for the second option, to create a virtual 141-PF keyboard and update it by scanning the P170-DH keypad asynchronously, occurred to me while I was writing the post and I included it at the last minute. If I'd implemented this in software rather than HDL I probably would have implemented the first option without further concern. But the more I thought about the circuitry required the more interested I became in the virtual keyboard idea. So that's what I've implemented.
The remapping code took about 130 lines of Verilog. The design centers around the virtual 141-PF keyboard, which is structured as a 8 column by 4 row matrix. Thus I defined the virtual keyboard matrix as an eight element array of 4-bit vectors:
reg [3:0] kb_matrix [0:7];
always @(posedge sys_clk) begin if (sample) begin case (1'b0) kp_col[1] : begin kb_feed <= kp_row[1]; // feed kb_matrix[7][2] <= kp_row[2]; // CE <- right arrow kb_matrix[1][1] <= kp_row[3]; // %+- kb_matrix[2][0] <= kp_row[4]; // #/diamond kb_matrix[7][3] <= kp_row[5]; // C <- CE/C end ... similar code for kp_col[2] through kp_col[7] here ... kp_col[8] : begin // kb_matrix[][] <= kp_row[1]; // Tax- kb_matrix[0][2] <= kp_row[2]; // M- <- ~ kb_matrix[0][3] <= kp_row[3]; // M+ <- Mdiamond kb_matrix[1][2] <= kp_row[4]; // M-= kb_matrix[1][3] <= kp_row[5]; // M+= end endcase end end
The kp_col vector drives the column outputs to the keypad. In sequence, at 250us intervals, one of these outputs is driven low by the FPGA logic. The row tracks pass through a Schmitt Trigger inverter, so if a key on that column is pressed, the corresponding kp_row input to the FPGA will go high. The "sample" signal goes high at the end of each interval, clocking the state of the kp_row bits into the appropriate flip-flops in the kb_matrix virtual keyboard.
The i4004 software scans the keyboard matrix by walking a "0" bit down an i4003 shift register, which has 10 outputs. Each of the first 8 outputs of the i4003 selects one column of the keyboard matrix, while the remaining two outputs select the encoded slide switch outputs.
In this emulation, the virtual keyboard matrix is read through a classic "sum of products" multiplexer: a set of AND gates whose outputs are ORed together. For clarity I chose to code this with "if" statements rather than boolean logic:
// kb_col selects which column is muxed onto kb_row always @(*) begin kb_row = 4'b0000; if (~kb_col[0]) kb_row = kb_row | kb_matrix[0]; if (~kb_col[1]) kb_row = kb_row | kb_matrix[1]; if (~kb_col[2]) kb_row = kb_row | kb_matrix[2]; if (~kb_col[3]) kb_row = kb_row | kb_matrix[3]; if (~kb_col[4]) kb_row = kb_row | kb_matrix[4]; if (~kb_col[5]) kb_row = kb_row | kb_matrix[5]; if (~kb_col[6]) kb_row = kb_row | kb_matrix[6]; if (~kb_col[7]) kb_row = kb_row | kb_matrix[7]; if (~kb_col[8]) kb_row = kb_row | kb_decimal; if (~kb_col[9]) kb_row = kb_row | kb_round; end
I also connected the kp_col, kp_row, kb_col, and kp_row signals to my debug header, and set up my logic analyzer to display these signals. By triggering on the falling edge of kp_col[1] I could easily watch the scanning of the P170-DH keypad, and by triggering on the falling edge of kb_col[0] I could watch the output of the virtual keyboard being scanned and validate that the remapping was correct.
Resource requirements for the keypad remap code are quite low: 28 slices of the 1,430 available. That includes the 32 flip-flops in the virtual keyboard matrix, the logic to encode the two slide switches to BCD, and the output mux.
The test code occupied another 22 slices. This includes the clock dividers, the kp_col and kb_col shifters, the kp_row input buffers, and the debug header output drivers.
Current draw on my bench power supply was about 25mA at about 7V during this test.
Note: The Busicom software scans the keyboard once each time the printer drum sector signal goes inactive. My emulation of the EP102 printer does this every 28ms (35.7Hz) because that is what the analysis team documented.
With the i4004 running with a clock period of 1.4us, each keyboard column line is driven low for 358.4us, or 32 instruction cycles. So so my guess of 29 instruction cycles (325us) per column was pretty close. With a clock period of 1.35us, 32 instructions would take 345.6us.
No comments:
Post a Comment